From cf96e7353eef60fd957d0051c48918f0b6dca186 Mon Sep 17 00:00:00 2001
From: Matthew Vernon
Date: Mon, 31 Aug 2026 21:36:38 +0100
Subject: [PATCH] New upstream version 10.48
---
ChangeLog | 14 +-
MODULE.bazel | 2 +-
Makefile.am | 14 +-
Makefile.in | 20 +-
NEWS | 18 +-
SECURITY.md | 13 +-
SUPPORT-LIFECYCLE.md | 226 ++++++++-
build.zig.zon | 2 +-
configure | 26 +-
configure.ac | 4 +-
doc/pcre2-config.1 | 2 +-
doc/pcre2-config.txt | 2 +-
doc/pcre2.3 | 2 +-
doc/pcre2.txt | 32 +-
doc/pcre2_callout_enumerate.3 | 2 +-
doc/pcre2_code_copy.3 | 2 +-
doc/pcre2_code_copy_with_tables.3 | 2 +-
doc/pcre2_code_free.3 | 2 +-
doc/pcre2_compile.3 | 2 +-
doc/pcre2_compile_context_copy.3 | 2 +-
doc/pcre2_compile_context_create.3 | 2 +-
doc/pcre2_compile_context_free.3 | 2 +-
doc/pcre2_config.3 | 2 +-
doc/pcre2_convert_context_copy.3 | 2 +-
doc/pcre2_convert_context_create.3 | 2 +-
doc/pcre2_convert_context_free.3 | 2 +-
doc/pcre2_converted_pattern_free.3 | 2 +-
doc/pcre2_dfa_match.3 | 2 +-
doc/pcre2_general_context_copy.3 | 2 +-
doc/pcre2_general_context_create.3 | 2 +-
doc/pcre2_general_context_free.3 | 2 +-
doc/pcre2_get_error_message.3 | 2 +-
doc/pcre2_get_mark.3 | 2 +-
doc/pcre2_get_match_data_heapframes_size.3 | 2 +-
doc/pcre2_get_match_data_size.3 | 2 +-
doc/pcre2_get_ovector_count.3 | 2 +-
doc/pcre2_get_ovector_pointer.3 | 2 +-
doc/pcre2_get_startchar.3 | 2 +-
doc/pcre2_jit_compile.3 | 2 +-
doc/pcre2_jit_free_unused_memory.3 | 2 +-
doc/pcre2_jit_match.3 | 2 +-
doc/pcre2_jit_stack_assign.3 | 2 +-
doc/pcre2_jit_stack_create.3 | 2 +-
doc/pcre2_jit_stack_free.3 | 2 +-
doc/pcre2_maketables.3 | 2 +-
doc/pcre2_maketables_free.3 | 2 +-
doc/pcre2_match.3 | 2 +-
doc/pcre2_match_context_copy.3 | 2 +-
doc/pcre2_match_context_create.3 | 2 +-
doc/pcre2_match_context_free.3 | 2 +-
doc/pcre2_match_data_create.3 | 2 +-
doc/pcre2_match_data_create_from_pattern.3 | 2 +-
doc/pcre2_match_data_free.3 | 2 +-
doc/pcre2_next_match.3 | 2 +-
doc/pcre2_pattern_convert.3 | 2 +-
doc/pcre2_pattern_info.3 | 2 +-
doc/pcre2_serialize_decode.3 | 2 +-
doc/pcre2_serialize_encode.3 | 2 +-
doc/pcre2_serialize_free.3 | 2 +-
doc/pcre2_serialize_get_number_of_codes.3 | 2 +-
doc/pcre2_set_bsr.3 | 2 +-
doc/pcre2_set_callout.3 | 2 +-
doc/pcre2_set_character_tables.3 | 2 +-
doc/pcre2_set_compile_extra_options.3 | 2 +-
doc/pcre2_set_compile_recursion_guard.3 | 2 +-
doc/pcre2_set_depth_limit.3 | 2 +-
doc/pcre2_set_glob_escape.3 | 2 +-
doc/pcre2_set_glob_separator.3 | 2 +-
doc/pcre2_set_heap_limit.3 | 2 +-
doc/pcre2_set_match_limit.3 | 2 +-
doc/pcre2_set_max_pattern_compiled_length.3 | 2 +-
doc/pcre2_set_max_pattern_length.3 | 2 +-
doc/pcre2_set_max_varlookbehind.3 | 2 +-
doc/pcre2_set_newline.3 | 2 +-
doc/pcre2_set_offset_limit.3 | 2 +-
doc/pcre2_set_optimize.3 | 2 +-
doc/pcre2_set_parens_nest_limit.3 | 2 +-
doc/pcre2_set_recursion_limit.3 | 2 +-
doc/pcre2_set_recursion_memory_management.3 | 2 +-
doc/pcre2_set_substitute_callout.3 | 2 +-
doc/pcre2_set_substitute_case_callout.3 | 2 +-
doc/pcre2_substitute.3 | 2 +-
doc/pcre2_substring_copy_byname.3 | 2 +-
doc/pcre2_substring_copy_bynumber.3 | 2 +-
doc/pcre2_substring_free.3 | 2 +-
doc/pcre2_substring_get_byname.3 | 2 +-
doc/pcre2_substring_get_bynumber.3 | 2 +-
doc/pcre2_substring_length_byname.3 | 2 +-
doc/pcre2_substring_length_bynumber.3 | 2 +-
doc/pcre2_substring_list_free.3 | 2 +-
doc/pcre2_substring_list_get.3 | 2 +-
doc/pcre2_substring_nametable_scan.3 | 2 +-
doc/pcre2_substring_number_from_name.3 | 2 +-
doc/pcre2api.3 | 2 +-
doc/pcre2build.3 | 2 +-
doc/pcre2callout.3 | 2 +-
doc/pcre2compat.3 | 2 +-
doc/pcre2convert.3 | 2 +-
doc/pcre2demo.3 | 2 +-
doc/pcre2grep.1 | 2 +-
doc/pcre2grep.txt | 2 +-
doc/pcre2jit.3 | 2 +-
doc/pcre2limits.3 | 2 +-
doc/pcre2matching.3 | 2 +-
doc/pcre2partial.3 | 2 +-
doc/pcre2pattern.3 | 2 +-
doc/pcre2perform.3 | 2 +-
doc/pcre2posix.3 | 2 +-
doc/pcre2sample.3 | 2 +-
doc/pcre2serialize.3 | 2 +-
doc/pcre2syntax.3 | 2 +-
doc/pcre2test.1 | 2 +-
doc/pcre2test.txt | 2 +-
doc/pcre2unicode.3 | 2 +-
patches/pcre2-10.37-Remove-real-POSIX.patch | 311 ++++++++++++
patches/pcre2-10.40-A-Fixed-a-unicode.patch | 19 +-
...pcre2-10.43-Avoid-LIMIT_HEAP-integer.patch | 65 +--
.../pcre2-10.43-Fix-heapframe-overflow.patch | 47 +-
.../pcre2-10.44-Fix-incorrect-compiling.patch | 44 +-
patches/pcre2-10.44-Fix-locking-region.patch | 31 +-
...2-10.45-Memory-reports-only-compiled.patch | 57 +--
patches/pcre2-10.47-Fix-for-callback.patch | 118 ++---
....48-Check-JIT-mode-before-validation.patch | 382 ++++++++++++++
...e2-10.48-Fix-DFA-workspace-overflows.patch | 149 ++++++
patches/pcre2-10.48-Fix-JIT-STR_END.patch | 34 ++
...e2-10.48-Fix-JIT-match-context-reuse.patch | 480 ++++++++++++++++++
...re2-10.48-Fix-allocation-byte-sizing.patch | 54 ++
...2-10.48-Fix-character-list-generator.patch | 113 +++++
...10.48-Fix-compiler-integer-overflows.patch | 200 ++++++++
...0.48-Fix-invalid-UTF-backwards-scans.patch | 212 ++++++++
...0.48-Fix-repeated-substitute-escapes.patch | 75 +++
...2-10.48-Fix-scan-prefix-repeat-reset.patch | 30 ++
...-Keep-escape-error-offset-in-pattern.patch | 92 ++++
...e2-10.48-Write-serialization-padding.patch | 80 +++
src/config.h.generic | 6 +-
src/pcre2.h.generic | 4 +-
src/pcre2_compile.c | 55 +-
src/pcre2_compile_class.c | 35 +-
src/pcre2_dfa_match.c | 44 +-
src/pcre2_extuni.c | 10 +-
src/pcre2_match.c | 10 +-
testdata/testinput10 | 10 +
testdata/testinput12 | 10 +
testdata/testinput6 | 7 +
testdata/testoutput10 | 12 +
testdata/testoutput12-16 | 12 +
testdata/testoutput12-32 | 12 +
testdata/testoutput6 | 8 +
148 files changed, 2985 insertions(+), 420 deletions(-)
create mode 100644 patches/pcre2-10.48-Check-JIT-mode-before-validation.patch
create mode 100644 patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch
create mode 100644 patches/pcre2-10.48-Fix-JIT-STR_END.patch
create mode 100644 patches/pcre2-10.48-Fix-JIT-match-context-reuse.patch
create mode 100644 patches/pcre2-10.48-Fix-allocation-byte-sizing.patch
create mode 100644 patches/pcre2-10.48-Fix-character-list-generator.patch
create mode 100644 patches/pcre2-10.48-Fix-compiler-integer-overflows.patch
create mode 100644 patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch
create mode 100644 patches/pcre2-10.48-Fix-repeated-substitute-escapes.patch
create mode 100644 patches/pcre2-10.48-Fix-scan-prefix-repeat-reset.patch
create mode 100644 patches/pcre2-10.48-Keep-escape-error-offset-in-pattern.patch
create mode 100644 patches/pcre2-10.48-Write-serialization-padding.patch
diff --git a/ChangeLog b/ChangeLog
index 8c67c7a..01fc8cd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,7 +8,7 @@ Internal changes which are not visible to clients of the library are mostly not
listed here.
-Version 10.48 27-August-2026
+Version 10.48 31-August-2026
----------------------------
1. (#826) [GHSA-q7rw-r7qq-2hx6] Initialized alignment padding in serialized
@@ -132,11 +132,17 @@ CMAKE_SHARED_LIBRARY_PREFIX_C is customized.
34. (#961, #962) Fixed two compilation issues preventing use of extended
(Boolean) character classes before a lookbehind, or inside a lookaround.
-35. [GHSA-fmgr-6ggq-9859] Withheld
+35. (GHSA-3r4p-g7gg-ppmf) Fixed an out-of-bounds write in DFA matching when
+using a heap limit; also fixed possible integer overflows which could cause
+under-allocation of the workspace.
-36. [GHSA-9qww-pwc4-77qq] Withheld
+36. (GHSA-fmgr-6ggq-9859) Added bounds checks for several integer overflows
+while compiling patterns on 32-bit CPUs, which could cause under-allocation
+followed by out-of-bounds writes.
-37. [GHSA-3r4p-g7gg-ppmf] Withheld
+37. (GHSA-9qww-pwc4-77qq) Applied lower buffer bound to prevent two
+out-of-bounds reads while scanning backwards through invalid UTF data with
+PCRE2_MATCH_INVALID_UTF.
Version 10.47 21-October-2025
diff --git a/MODULE.bazel b/MODULE.bazel
index 7024259..ac5e974 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -1,6 +1,6 @@
module(
name = "pcre2",
- version = "10.48-RC1",
+ version = "10.48",
compatibility_level = 1,
)
diff --git a/Makefile.am b/Makefile.am
index f6f584a..e112b5c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -302,7 +302,19 @@ EXTRA_DIST += \
patches/pcre2-10.44-Fix-incorrect-compiling.patch \
patches/pcre2-10.44-Fix-locking-region.patch \
patches/pcre2-10.45-Memory-reports-only-compiled.patch \
- patches/pcre2-10.47-Fix-for-callback.patch
+ patches/pcre2-10.47-Fix-for-callback.patch \
+ patches/pcre2-10.48-Check-JIT-mode-before-validation.patch \
+ patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch \
+ patches/pcre2-10.48-Fix-JIT-STR_END.patch \
+ patches/pcre2-10.48-Fix-JIT-match-context-reuse.patch \
+ patches/pcre2-10.48-Fix-allocation-byte-sizing.patch \
+ patches/pcre2-10.48-Fix-character-list-generator.patch \
+ patches/pcre2-10.48-Fix-compiler-integer-overflows.patch \
+ patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch \
+ patches/pcre2-10.48-Fix-repeated-substitute-escapes.patch \
+ patches/pcre2-10.48-Fix-scan-prefix-repeat-reset.patch \
+ patches/pcre2-10.48-Keep-escape-error-offset-in-pattern.patch \
+ patches/pcre2-10.48-Write-serialization-padding.patch
# These are support files for building with Bazel or Zig
diff --git a/Makefile.in b/Makefile.in
index 2a26fc9..756f314 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1373,10 +1373,22 @@ EXTRA_DIST = m4/ax_pthread.m4 m4/pcre2_check_vscript.m4 \
patches/pcre2-10.44-Fix-incorrect-compiling.patch \
patches/pcre2-10.44-Fix-locking-region.patch \
patches/pcre2-10.45-Memory-reports-only-compiled.patch \
- patches/pcre2-10.47-Fix-for-callback.patch BUILD.bazel \
- MODULE.bazel build.zig build.zig.zon vms/configure.com \
- vms/openvms_readme.txt vms/pcre2.h_patch vms/stdint.h \
- src/pcre2.h.generic src/config.h.generic \
+ patches/pcre2-10.47-Fix-for-callback.patch \
+ patches/pcre2-10.48-Check-JIT-mode-before-validation.patch \
+ patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch \
+ patches/pcre2-10.48-Fix-JIT-STR_END.patch \
+ patches/pcre2-10.48-Fix-JIT-match-context-reuse.patch \
+ patches/pcre2-10.48-Fix-allocation-byte-sizing.patch \
+ patches/pcre2-10.48-Fix-character-list-generator.patch \
+ patches/pcre2-10.48-Fix-compiler-integer-overflows.patch \
+ patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch \
+ patches/pcre2-10.48-Fix-repeated-substitute-escapes.patch \
+ patches/pcre2-10.48-Fix-scan-prefix-repeat-reset.patch \
+ patches/pcre2-10.48-Keep-escape-error-offset-in-pattern.patch \
+ patches/pcre2-10.48-Write-serialization-padding.patch \
+ BUILD.bazel MODULE.bazel build.zig build.zig.zon \
+ vms/configure.com vms/openvms_readme.txt vms/pcre2.h_patch \
+ vms/stdint.h src/pcre2.h.generic src/config.h.generic \
src/pcre2_chartables.c.dist \
src/pcre2_chartables.c.ebcdic-1047-nl15 \
src/pcre2_chartables.c.ebcdic-1047-nl25 deps/sljit/LICENSE \
diff --git a/NEWS b/NEWS
index 94d81b3..13cc4c6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,7 @@
News about PCRE2 releases
-------------------------
-Version 10.48 27-August-2026
+Version 10.48 31-August-2026
----------------------------
This is a regular release, incorporating security fixes along with small
@@ -10,6 +10,10 @@ improvements and fixes to library behaviour.
Only changes to behaviour, changes to the API, and other significant changes
are described here. Please see the ChangeLog and Git log for further details.
+As well as the tarball and Git tag for this release, there are detailed
+instructions for backporting security and correctness fixes, for the last
+five years of releases.
+
* (Git change) Renamed the default development branch from master to main.
* (Maintenance change) Added a five-year support lifecycle policy and
@@ -25,11 +29,17 @@ out-of-bounds read can occur if the match is attempted against invalid UTF input
is called on untrusted input on platforms with 32-bit size_t, an out-of-bounds
heap write can occur.
-* (Security fix, GHSA-fmgr-6ggq-9859) Withheld
+* (Security fix, GHSA-3r4p-g7gg-ppmf) Fixed an out-of-bounds write in DFA
+matching when using a heap limit; also fixed possible integer overflows which
+could cause under-allocation of the workspace.
-* (Security fix, GHSA-9qww-pwc4-77qq) Withheld
+* (Security fix, GHSA-fmgr-6ggq-9859) Added bounds checks for several integer
+overflows while compiling patterns on 32-bit CPUs, which could cause
+under-allocation followed by out-of-bounds writes.
-* (Security fix, GHSA-3r4p-g7gg-ppmf) Withheld
+* (Security fix, GHSA-9qww-pwc4-77qq) Applied lower buffer bound to prevent
+two out-of-bounds reads while scanning backwards through invalid UTF data with
+PCRE2_MATCH_INVALID_UTF.
* (Matching correctness) Fixed several matching issues:
- A JIT-specific matching bug affecting prefix scanning on patterns with
diff --git a/SECURITY.md b/SECURITY.md
index 4bbe5cd..b5dba4f 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -61,8 +61,17 @@ vulnerability publicly, where advance notification is possible.
Previous vulnerabilities
------------------------
-* CVE-2025-58050 (August 2025). Affects 10.45 only (not earlier), and is fixed
- in 10.46.
+* GHSA-2p8c-ff85-vh9x (July 2026). Affects 10.47 and earlier, and is fixed
+ in 10.48.
+* GHSA-3r4p-g7gg-ppmf (July 2026). Affects 10.32-10.47, and is fixed in 10.48.
+* GHSA-q8g2-wprr-34m9 (May 2026). Affects 10.30-10.47, and is fixed in 10.48.
+* GHSA-9qww-pwc4-77qq (May 2026). Affects 10.34-10.47, and is fixed in 10.48.
+* GHSA-fmgr-6ggq-9859 (January 2026). Affects 10.47 and earlier, and is fixed
+ in 10.48.
+* GHSA-q7rw-r7qq-2hx6 (October 2025). Affects 10.45 and later, and is fixed in
+ 10.48.
+* CVE-2025-58050 [GHSA-c2gv-xgf5-5cc2] (August 2025). Affects 10.45 only (not
+ earlier), and is fixed in 10.46.
* CVE-2022-41409 (July 2023). Only affects test code; no expected impact. Fixed
in 10.41.
* CVE-2022-1587 and CVE-2022-1586 (May 2020). Affect versions before 10.40, and
diff --git a/SUPPORT-LIFECYCLE.md b/SUPPORT-LIFECYCLE.md
index 7d067b0..a4ff17f 100644
--- a/SUPPORT-LIFECYCLE.md
+++ b/SUPPORT-LIFECYCLE.md
@@ -25,8 +25,24 @@ support status and any new lifecycle recommendations.
* Check this document on each release of PCRE2.
* Each version of PCRE2 that you are supporting should be listed here.
-* Check for any changes in the "patches to apply" section, and consider
- backporting these.
+* Check for changes in that version's "backports to apply" section. Apply
+ commits from the release branch according to your distribution's backporting
+ criteria.
+
+The patches are made available in two ways:
+
+* For tarball-based workflows, I am including the dump of the commits
+ containing the changes to be backported. These flat files record the
+ canonical changes, but may require adaptation to an old release.
+
+* For git-based workflows (preferable), I am publishing a release branch for
+ each release - for example, `release/pcre2-10.47`. This branch will always
+ be ahead of the `pcre2-10.47` release tag, and the additional commits
+ consist of the cherry-picked commits, with approved and tested conflict
+ resolutions applied.
+
+ To apply all recommended commits for a release, fetch its branch and
+ merge (or cherry-pick) the commits after the release tag.
## Support Policy
@@ -90,12 +106,34 @@ lifecycle for old (not-latest) PCRE2 releases.
## Supported Versions
-Below is the list of supported PCRE2 versions. For each version, specific
-recommendations and backported fixes (if any) are provided.
+Below is the list of PCRE2 versions supported by upstream distributors. For
+each version, specific recommendations and backported fixes (if any) are
+provided.
+
+### PCRE2 10.23 14-February-2017
+
+* Shipped in RHEL 7 (paid Extended Life Cycle Support ends 31 May 2029).
+
+I am not providing a recommendation of what patches to apply. This release is
+beyond PCRE2's standard five-year support period and is maintained only through
+an extended-support programme.
+
+### PCRE2 10.31 12-February-2018
+
+* Shipped in Ubuntu 18.04 "Bionic Beaver" (Expanded Security Maintenance ends
+ April 2028).
+* Shipped in SUSE Linux Enterprise Server 15 SP1, SP2 and SP3 (paid LTSS
+ Reactive support ends 31 January 2027, 31 December 2027 and 31 December
+ 2028, respectively).
+
+I am not providing a recommendation of what patches to apply. These releases
+are beyond PCRE2's standard five-year support period and are maintained only
+through extended-support programmes.
### PCRE2 10.32 10-September-2018
-* Shipped in RHEL/CentOS 8 (EOL 31 May 2024).
+* Shipped in RHEL 8 (Maintenance Support ends 31 May 2029; paid Extended Life
+ Cycle support ends 31 May 2033).
This version is older than 5 years, but remains listed in SUPPORT-LIFECYCLE.md
potentially until May 2029 (end of "Maintenance Support" for RHEL 8), in
@@ -111,6 +149,17 @@ https://gitlab.com/redhat/centos-stream/rpms/pcre2/-/tree/c8s?ref_type=heads
The most serious of these was the backported mitigation for CVE-2019-20454 from
the fix in 10.34.
+### PCRE2 10.34 21-November-2019
+
+* Shipped in Ubuntu 20.04 "Focal Fossa" (Expanded Security Maintenance ends
+ April 2030).
+* Shipped in SUSE Linux Enterprise Server 12 SP5 (paid LTSS ends 31 October
+ 2027).
+
+I am not providing a recommendation of what patches to apply. These releases
+are beyond PCRE2's standard five-year support period and are maintained only
+through extended-support programmes.
+
### PCRE2 10.36 04-December-2020
* Shipped in Debian 11 "Bullseye" (EOL 31 Aug 2026).
@@ -140,10 +189,18 @@ Do not use (update to 10.39).
### PCRE2 10.39 29-October-2021
* Shipped in Ubuntu 22.04 "Jammy Jellyfish" (EOL 01 Apr 2027).
-
-I am not providing a recommendation of what patches to apply. Distributors still
-shipping this release have likely frozen their codebase at this point, since the
-release of Ubuntu 24.04.
+* Shipped in SUSE Linux Enterprise Server 15 SP4 and SP5 (paid LTSS ends 31
+ December 2026 and 31 December 2027, respectively).
+
+Backports to apply:
+* `patches/pcre2-10.40-A-Fixed-a-unicode.patch`
+* `patches/pcre2-10.40-B-Fixed-an-issue-affecting.patch`
+* `patches/pcre2-10.48-Fix-JIT-match-context-reuse.patch`
+* `patches/pcre2-10.48-Check-JIT-mode-before-validation.patch`
+* `patches/pcre2-10.48-Fix-allocation-byte-sizing.patch`
+* `patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch`
+* `patches/pcre2-10.48-Fix-compiler-integer-overflows.patch`
+* `patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch`
Patches introduced:
* `patches/pcre2-10.39-Fix-incorrect-detection.patch`: Significant bugfix for
@@ -151,11 +208,17 @@ Patches introduced:
### PCRE2 10.40 15-April-2022
-* Shipped in RHEL/CentOS 9 (EOL 31 May 2027).
+* Shipped in RHEL 9 (Full Support ends 31 May 2027; Maintenance Support ends 31
+ May 2032; paid Extended Life Cycle support ends 31 May 2036).
+* Shipped in CentOS Stream 9 (EOL 31 May 2027).
-I am not providing a recommendation of what patches to apply. Distributors still
-shipping this release have likely frozen their codebase at this point, since the
-release of RHEL 10.
+Backports to apply:
+* `patches/pcre2-10.48-Fix-JIT-match-context-reuse.patch`
+* `patches/pcre2-10.48-Check-JIT-mode-before-validation.patch`
+* `patches/pcre2-10.48-Fix-allocation-byte-sizing.patch`
+* `patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch`
+* `patches/pcre2-10.48-Fix-compiler-integer-overflows.patch`
+* `patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch`
For the record, RHEL/CentOS 9 ships rather more backported patches than other
distributions:
@@ -166,9 +229,11 @@ tested them myself for compatibility with 10.40 or other earlier releases.
Patches introduced:
* `patches/pcre2-10.40-A-Fixed-a-unicode.patch`: Fixed CVE-2022-1586. This
- affects all recent previous versions of PCRE2.
+ should be assumed to affect all previous versions of PCRE2 (lower bound of
+ affected releases unconfirmed).
* `patches/pcre2-10.40-B-Fixed-an-issue-affecting.patch`: Fixed CVE-2022-1587.
- This affects all recent previous versions of PCRE2.
+ This should be assumed to affect all previous versions of PCRE2 (lower bound
+ of affected releases unconfirmed).
### PCRE2 10.41 06-December-2022
@@ -180,25 +245,39 @@ for the test suite, so this fix is not backported.
### PCRE2 10.42 11-December-2022
* Shipped in Debian 12 "Bookworm" (EOL 30 Jun 2028).
-* Shipped in Ubuntu 24.04 "Noble Numbat" (EOL 25 Apr 2029).
+* Shipped in Ubuntu 24.04 "Noble Numbat" (EOL 31 May 2029).
+* Shipped in SUSE Linux Enterprise Server 15 SP6 and SP7 (paid LTSS ends 31
+ December 2028 and general support ends 31 July 2031, respectively).
Users on RISC-V are advised to update to 10.43, or not use the JIT unless using
a backport for https://github.com/zherczeg/sljit/pull/223. Given the small
RISC-V userbase (especially on older releases), disabling the JIT for RISC-V
builds is likely acceptable.
-Patches to apply:
+Backports to apply:
* `patches/pcre2-10.43-Avoid-LIMIT_HEAP-integer.patch`
* `patches/pcre2-10.43-Fix-heapframe-overflow.patch`
+* `patches/pcre2-10.48-Fix-JIT-match-context-reuse.patch`
+* `patches/pcre2-10.48-Check-JIT-mode-before-validation.patch`
+* `patches/pcre2-10.48-Fix-allocation-byte-sizing.patch`
+* `patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch`
+* `patches/pcre2-10.48-Fix-compiler-integer-overflows.patch`
+* `patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch`
### PCRE2 10.43 16-February-2024
-* Shipped in Alpine 3.20 (EOL 01 Apr 2026)
-* Shipped in Alpine 3.21 (EOL 01 Nov 2026)
+* Shipped in Alpine 3.21 (EOL 01 Nov 2026).
-Patches to apply:
+Backports to apply:
* `patches/pcre2-10.44-Fix-locking-region.patch`
* `patches/pcre2-10.44-Fix-incorrect-compiling.patch`
+* `patches/pcre2-10.48-Fix-JIT-STR_END.patch`
+* `patches/pcre2-10.48-Fix-JIT-match-context-reuse.patch`
+* `patches/pcre2-10.48-Check-JIT-mode-before-validation.patch`
+* `patches/pcre2-10.48-Fix-allocation-byte-sizing.patch`
+* `patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch`
+* `patches/pcre2-10.48-Fix-compiler-integer-overflows.patch`
+* `patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch`
Patches introduced:
* `patches/pcre2-10.43-Avoid-LIMIT_HEAP-integer.patch`: Fix integer overflow in
@@ -207,15 +286,24 @@ Patches introduced:
heap-allocated frames vector. This patch is therefore recommended for
backporting to 10.42 only.
* `patches/pcre2-10.43-Fix-heapframe-overflow.patch`: Fix buffer overrun in
- handling of LIMIT_HEAP. These patches can be backported to all recent previous
- versions (since LIMIT_HEAP was introduced in 10.30).
+ handling of LIMIT_HEAP. The regression was introduced in d90fb238 in PCRE2
+ 10.41, so the patch is for backporting to 10.41-42.
### PCRE2 10.44 07-June-2024
-* Shipped in RHEL/CentOS 10 (EOL 31 May 2030).
+* Shipped in RHEL 10 (Full Support ends 31 May 2030; Maintenance Support ends
+ 31 May 2035; paid Extended Life Cycle support ends 31 May 2039).
+* Shipped in CentOS Stream 10 (EOL 31 May 2030).
-Patches to apply:
+Backports to apply:
* `patches/pcre2-10.45-Memory-reports-only-compiled.patch`
+* `patches/pcre2-10.48-Fix-JIT-STR_END.patch`
+* `patches/pcre2-10.48-Fix-JIT-match-context-reuse.patch`
+* `patches/pcre2-10.48-Check-JIT-mode-before-validation.patch`
+* `patches/pcre2-10.48-Fix-allocation-byte-sizing.patch`
+* `patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch`
+* `patches/pcre2-10.48-Fix-compiler-integer-overflows.patch`
+* `patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch`
Patches introduced:
* `patches/pcre2-10.44-Fix-locking-region.patch`: To be backported to 10.43 only
@@ -228,6 +316,10 @@ Patches introduced:
### PCRE2 10.45 05-February-2025
+* Shipped in openSUSE Leap 16.0 (EOL 31 October 2027).
+* Shipped in SUSE Linux Enterprise Server 16.0 (general support ends 30
+ November 2027).
+
Do not use (update to 10.46, which is is a drop-in compatible release with a
security fix).
@@ -239,16 +331,47 @@ Patches introduced:
### PCRE2 10.46 27-August-2025
* Shipped in Debian 13 "Trixie" (EOL 30 Jun 2030).
-* Shipped in Alpine 3.22 (EOL 01 May 2027)
+* Shipped in Ubuntu 26.04 "Resolute Raccoon" (EOL 30 April 2031).
+* Shipped in Alpine 3.22 (EOL 01 May 2027).
+* Shipped in NixOS 26.05 (EOL 31 December 2026).
Introduced the fix for CVE-2025-58050. This only affects 10.45. Do not backport
the patch (just update to 10.46).
-Patches to apply:
+Backports to apply:
* `patches/pcre2-10.47-Fix-for-callback.patch`
+* `patches/pcre2-10.48-Write-serialization-padding.patch`
+* `patches/pcre2-10.48-Fix-character-list-generator.patch`
+* `patches/pcre2-10.48-Fix-scan-prefix-repeat-reset.patch`
+* `patches/pcre2-10.48-Fix-JIT-STR_END.patch`
+* `patches/pcre2-10.48-Fix-JIT-match-context-reuse.patch`
+* `patches/pcre2-10.48-Check-JIT-mode-before-validation.patch`
+* `patches/pcre2-10.48-Fix-allocation-byte-sizing.patch`
+* `patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch`
+* `patches/pcre2-10.48-Fix-compiler-integer-overflows.patch`
+* `patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch`
### PCRE2 10.47 21-October-2025
+* Shipped in Fedora 43 (EOL 09 December 2026) and Fedora 44 (EOL 02 June
+ 2027).
+* Shipped in Alpine 3.23 (EOL 01 November 2027) and Alpine 3.24 (EOL 01 June
+ 2028).
+
+Backports to apply:
+* `patches/pcre2-10.48-Write-serialization-padding.patch`
+* `patches/pcre2-10.48-Fix-character-list-generator.patch`
+* `patches/pcre2-10.48-Fix-repeated-substitute-escapes.patch`
+* `patches/pcre2-10.48-Fix-scan-prefix-repeat-reset.patch`
+* `patches/pcre2-10.48-Fix-JIT-STR_END.patch`
+* `patches/pcre2-10.48-Fix-JIT-match-context-reuse.patch`
+* `patches/pcre2-10.48-Check-JIT-mode-before-validation.patch`
+* `patches/pcre2-10.48-Fix-allocation-byte-sizing.patch`
+* `patches/pcre2-10.48-Keep-escape-error-offset-in-pattern.patch`
+* `patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch`
+* `patches/pcre2-10.48-Fix-compiler-integer-overflows.patch`
+* `patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch`
+
Patches introduced:
* `patches/pcre2-10.47-Fix-for-callback.patch`: A fix for a significant memory
read overrun in a function rarely called by applications, to be backported to
@@ -257,6 +380,53 @@ Patches introduced:
fixing crashes and out-of-bounds memory reads in the previous, legacy AArch64
JIT. This is probably not possible to backport.
-### PCRE2 10.48 27-August-2026
+### PCRE2 10.48 31-August-2026
-**To be confirmed.**
+Patches introduced:
+* `patches/pcre2-10.48-Write-serialization-padding.patch`: Initializes
+ character-list padding before serialization, preventing a two-byte
+ information disclosure (GHSA-q7rw-r7qq-2hx6). The affected representation
+ was introduced in 10.45; affected releases are 10.45-10.47.
+* `patches/pcre2-10.48-Fix-character-list-generator.patch`: Fixes incorrect
+ compilation and false-negative matches for Unicode character lists around
+ U+0100 and ranges crossing U+00FF. The affected representation was
+ introduced in 10.45; affected releases are 10.45-10.47.
+* `patches/pcre2-10.48-Fix-repeated-substitute-escapes.patch`: Fixes incorrect
+ conditional substitution output and errors after consecutive extended
+ replacement escapes. This regression was introduced in 10.47 and affects
+ 10.47 only.
+* `patches/pcre2-10.48-Fix-scan-prefix-repeat-reset.patch`: Fixes JIT false
+ negatives caused by stale repeat state during prefix scanning. The affected
+ scan-prefix implementation was introduced in 10.45; affected releases are
+ 10.45-10.47.
+* `patches/pcre2-10.48-Fix-JIT-STR_END.patch`: Restores `STR_END` while JIT
+ backtracks through non-atomic variable-length lookbehinds. The affected JIT
+ support was introduced in 10.43; affected releases are 10.43-10.47.
+* `patches/pcre2-10.48-Fix-JIT-match-context-reuse.patch`: Prevents direct
+ `pcre2_jit_match()` reuse from leaking a copied subject, retaining stale
+ ownership state, or freeing caller-owned memory. Copied-subject support was
+ introduced in 10.33; affected releases are 10.33-10.47.
+* `patches/pcre2-10.48-Check-JIT-mode-before-validation.patch`: Checks that the
+ requested JIT mode exists before JIT validation and execution
+ (GHSA-2p8c-ff85-vh9x). The accompanying regression test is part of the same
+ backport series. The affected invalid-UTF fallback was introduced in 10.34;
+ affected releases are 10.34-10.47.
+* `patches/pcre2-10.48-Fix-allocation-byte-sizing.patch`: Uses byte sizes for
+ two allocations and adds overflow checks (GHSA-q8g2-wprr-34m9). One affected
+ allocation has been confirmed as far back as PCRE2 10.00; affected releases
+ are 10.47 and earlier.
+* `patches/pcre2-10.48-Keep-escape-error-offset-in-pattern.patch`: Keeps error
+ offsets within malformed patterns ending in incomplete `\x{`, `\o{`, or
+ `\N{U+` escapes. This regression was introduced in 10.47 and affects 10.47
+ only.
+* `patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch`: Prevents two
+ out-of-bounds reads while scanning backwards through invalid UTF data
+ (GHSA-9qww-pwc4-77qq). Invalid-UTF matching was introduced in 10.34; affected
+ releases are 10.34-10.47.
+* `patches/pcre2-10.48-Fix-compiler-integer-overflows.patch`: Adds bounds checks
+ for several integer overflows while compiling patterns
+ (GHSA-fmgr-6ggq-9859). The affected generic calculations have been confirmed
+ in PCRE2 10.00; affected releases are 10.47 and earlier.
+* `patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch`: Prevents workspace
+ size and offset overflows in DFA matching (GHSA-3r4p-g7gg-ppmf). The affected
+ heap workspace was introduced in 10.32; affected releases are 10.32-10.47.
diff --git a/build.zig.zon b/build.zig.zon
index a977415..eda9011 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -1,6 +1,6 @@
.{
.name = .pcre2,
- .version = "10.48.0-RC1",
+ .version = "10.48.0",
// Do NOT change this for new releases.
// DO change this if making a fork of PCRE2 which is used by any Zig clients.
diff --git a/configure b/configure
index de94aeb..f0deee0 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for PCRE2 10.48-RC1.
+# Generated by GNU Autoconf 2.71 for PCRE2 10.48.
#
#
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
@@ -626,8 +626,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='PCRE2'
PACKAGE_TARNAME='pcre2'
-PACKAGE_VERSION='10.48-RC1'
-PACKAGE_STRING='PCRE2 10.48-RC1'
+PACKAGE_VERSION='10.48'
+PACKAGE_STRING='PCRE2 10.48'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1480,7 +1480,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures PCRE2 10.48-RC1 to adapt to many kinds of systems.
+\`configure' configures PCRE2 10.48 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1551,7 +1551,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of PCRE2 10.48-RC1:";;
+ short | recursive ) echo "Configuration of PCRE2 10.48:";;
esac
cat <<\_ACEOF
@@ -1748,7 +1748,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-PCRE2 configure 10.48-RC1
+PCRE2 configure 10.48
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2141,7 +2141,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by PCRE2 $as_me 10.48-RC1, which was
+It was created by PCRE2 $as_me 10.48, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -3413,7 +3413,7 @@ fi
# Define the identity of the package.
PACKAGE='pcre2'
- VERSION='10.48-RC1'
+ VERSION='10.48'
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -14229,7 +14229,7 @@ Usage: $0 [OPTIONS]
Report bugs to ."
lt_cl_version="\
-PCRE2 config.lt 10.48-RC1
+PCRE2 config.lt 10.48
configured by $0, generated by GNU Autoconf 2.71.
Copyright (C) 2011 Free Software Foundation, Inc.
@@ -15849,8 +15849,8 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
PCRE2_MAJOR="10"
PCRE2_MINOR="48"
-PCRE2_PRERELEASE="-RC1"
-PCRE2_DATE="2026-08-27"
+PCRE2_PRERELEASE=""
+PCRE2_DATE="2026-08-31"
if test "$PCRE2_MINOR" = "08" -o "$PCRE2_MINOR" = "09"
then
@@ -19548,7 +19548,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by PCRE2 $as_me 10.48-RC1, which was
+This file was extended by PCRE2 $as_me 10.48, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -19616,7 +19616,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
-PCRE2 config.status 10.48-RC1
+PCRE2 config.status 10.48
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 8592c2e..62b1308 100644
--- a/configure.ac
+++ b/configure.ac
@@ -10,8 +10,8 @@ dnl be defined as -RC2, for example. For real releases, it should be empty.
m4_define(pcre2_major, [10])
m4_define(pcre2_minor, [48])
-m4_define(pcre2_prerelease, [-RC1])
-m4_define(pcre2_date, [2026-08-27])
+m4_define(pcre2_prerelease, [])
+m4_define(pcre2_date, [2026-08-31])
# Libtool shared library interface versions (current:revision:age)
m4_define(libpcre2_8_version, [16:0:16])
diff --git a/doc/pcre2-config.1 b/doc/pcre2-config.1
index e72663f..4c99a15 100644
--- a/doc/pcre2-config.1
+++ b/doc/pcre2-config.1
@@ -1,4 +1,4 @@
-.TH PCRE2-CONFIG 1 "22 February 2025" "PCRE2 10.48-RC1"
+.TH PCRE2-CONFIG 1 "22 February 2025" "PCRE2 10.48"
.SH NAME
pcre2-config - program to return PCRE2 configuration
.SH SYNOPSIS
diff --git a/doc/pcre2-config.txt b/doc/pcre2-config.txt
index c134a6a..b1a7070 100644
--- a/doc/pcre2-config.txt
+++ b/doc/pcre2-config.txt
@@ -81,4 +81,4 @@ REVISION
Last updated: 22 February 2025
-PCRE2 10.48-RC1 22 February 2025 PCRE2-CONFIG(1)
+PCRE2 10.48 22 February 2025 PCRE2-CONFIG(1)
diff --git a/doc/pcre2.3 b/doc/pcre2.3
index 0698b67..ce4b04c 100644
--- a/doc/pcre2.3
+++ b/doc/pcre2.3
@@ -1,4 +1,4 @@
-.TH PCRE2 3 "22 February 2025" "PCRE2 10.48-RC1"
+.TH PCRE2 3 "22 February 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH INTRODUCTION
diff --git a/doc/pcre2.txt b/doc/pcre2.txt
index f934cd2..dc2cee1 100644
--- a/doc/pcre2.txt
+++ b/doc/pcre2.txt
@@ -189,7 +189,7 @@ REVISION
Copyright (c) 1997-2021 University of Cambridge.
-PCRE2 10.48-RC1 22 February 2025 PCRE2(3)
+PCRE2 10.48 22 February 2025 PCRE2(3)
------------------------------------------------------------------------------
@@ -4440,7 +4440,7 @@ REVISION
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.48-RC1 08 December 2025 PCRE2API(3)
+PCRE2 10.48 08 December 2025 PCRE2API(3)
------------------------------------------------------------------------------
@@ -5087,7 +5087,7 @@ REVISION
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.48-RC1 17 October 2025 PCRE2BUILD(3)
+PCRE2 10.48 17 October 2025 PCRE2BUILD(3)
------------------------------------------------------------------------------
@@ -5520,7 +5520,7 @@ REVISION
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.48-RC1 26 February 2025 PCRE2CALLOUT(3)
+PCRE2 10.48 26 February 2025 PCRE2CALLOUT(3)
------------------------------------------------------------------------------
@@ -5779,7 +5779,7 @@ REVISION
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.48-RC1 02 June 2025 PCRE2COMPAT(3)
+PCRE2 10.48 02 June 2025 PCRE2COMPAT(3)
------------------------------------------------------------------------------
@@ -6234,7 +6234,7 @@ REVISION
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.48-RC1 08 August 2026 PCRE2JIT(3)
+PCRE2 10.48 08 August 2026 PCRE2JIT(3)
------------------------------------------------------------------------------
@@ -6319,7 +6319,7 @@ REVISION
Copyright (c) 1997-2023 University of Cambridge.
-PCRE2 10.48-RC1 03 September 2025 PCRE2LIMITS(3)
+PCRE2 10.48 03 September 2025 PCRE2LIMITS(3)
------------------------------------------------------------------------------
@@ -6552,7 +6552,7 @@ REVISION
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.48-RC1 22 February 2025 PCRE2MATCHING(3)
+PCRE2 10.48 22 February 2025 PCRE2MATCHING(3)
------------------------------------------------------------------------------
@@ -6949,7 +6949,7 @@ REVISION
Copyright (c) 1997-2019 University of Cambridge.
-PCRE2 10.48-RC1 16 August 2026 PCRE2PARTIAL(3)
+PCRE2 10.48 16 August 2026 PCRE2PARTIAL(3)
------------------------------------------------------------------------------
@@ -10818,7 +10818,7 @@ REVISION
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.48-RC1 25 October 2025 PCRE2PATTERN(3)
+PCRE2 10.48 25 October 2025 PCRE2PATTERN(3)
------------------------------------------------------------------------------
@@ -11073,7 +11073,7 @@ REVISION
Copyright (c) 1997-2022 University of Cambridge.
-PCRE2 10.48-RC1 06 December 2022 PCRE2PERFORM(3)
+PCRE2 10.48 06 December 2022 PCRE2PERFORM(3)
------------------------------------------------------------------------------
@@ -11431,7 +11431,7 @@ REVISION
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.48-RC1 27 November 2024 PCRE2POSIX(3)
+PCRE2 10.48 27 November 2024 PCRE2POSIX(3)
------------------------------------------------------------------------------
@@ -11525,7 +11525,7 @@ REVISION
Copyright (c) 1997-2016 University of Cambridge.
-PCRE2 10.48-RC1 28 February 2025 PCRE2SAMPLE(3)
+PCRE2 10.48 28 February 2025 PCRE2SAMPLE(3)
------------------------------------------------------------------------------
PCRE2SERIALIZE(3) Library Functions Manual PCRE2SERIALIZE(3)
@@ -11716,7 +11716,7 @@ REVISION
Copyright (c) 1997-2018 University of Cambridge.
-PCRE2 10.48-RC1 19 January 2024 PCRE2SERIALIZE(3)
+PCRE2 10.48 19 January 2024 PCRE2SERIALIZE(3)
------------------------------------------------------------------------------
@@ -12448,7 +12448,7 @@ REVISION
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.48-RC1 14 October 2025 PCRE2SYNTAX(3)
+PCRE2 10.48 14 October 2025 PCRE2SYNTAX(3)
------------------------------------------------------------------------------
@@ -12943,7 +12943,7 @@ REVISION
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.48-RC1 27 November 2024 PCRE2UNICODE(3)
+PCRE2 10.48 27 November 2024 PCRE2UNICODE(3)
------------------------------------------------------------------------------
diff --git a/doc/pcre2_callout_enumerate.3 b/doc/pcre2_callout_enumerate.3
index 32bfa33..53b64ae 100644
--- a/doc/pcre2_callout_enumerate.3
+++ b/doc/pcre2_callout_enumerate.3
@@ -1,4 +1,4 @@
-.TH PCRE2_COMPILE 3 "23 March 2017" "PCRE2 10.48-RC1"
+.TH PCRE2_COMPILE 3 "23 March 2017" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_code_copy.3 b/doc/pcre2_code_copy.3
index c5038ab..9fa48c0 100644
--- a/doc/pcre2_code_copy.3
+++ b/doc/pcre2_code_copy.3
@@ -1,4 +1,4 @@
-.TH PCRE2_CODE_COPY 3 "22 November 2016" "PCRE2 10.48-RC1"
+.TH PCRE2_CODE_COPY 3 "22 November 2016" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_code_copy_with_tables.3 b/doc/pcre2_code_copy_with_tables.3
index 4252e6d..77bb7f7 100644
--- a/doc/pcre2_code_copy_with_tables.3
+++ b/doc/pcre2_code_copy_with_tables.3
@@ -1,4 +1,4 @@
-.TH PCRE2_CODE_COPY 3 "16 January 2017" "PCRE2 10.48-RC1"
+.TH PCRE2_CODE_COPY 3 "16 January 2017" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_code_free.3 b/doc/pcre2_code_free.3
index a538b1e..cfd1f62 100644
--- a/doc/pcre2_code_free.3
+++ b/doc/pcre2_code_free.3
@@ -1,4 +1,4 @@
-.TH PCRE2_CODE_FREE 3 "28 June 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_CODE_FREE 3 "28 June 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_compile.3 b/doc/pcre2_compile.3
index ec3bb9a..4c0eccd 100644
--- a/doc/pcre2_compile.3
+++ b/doc/pcre2_compile.3
@@ -1,4 +1,4 @@
-.TH PCRE2_COMPILE 3 "30 October 2024" "PCRE2 10.48-RC1"
+.TH PCRE2_COMPILE 3 "30 October 2024" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_compile_context_copy.3 b/doc/pcre2_compile_context_copy.3
index 15a85fb..b8ec3d7 100644
--- a/doc/pcre2_compile_context_copy.3
+++ b/doc/pcre2_compile_context_copy.3
@@ -1,4 +1,4 @@
-.TH PCRE2_COMPILE_CONTEXT_COPY 3 "25 October 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_COMPILE_CONTEXT_COPY 3 "25 October 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_compile_context_create.3 b/doc/pcre2_compile_context_create.3
index 87f7b52..3522a05 100644
--- a/doc/pcre2_compile_context_create.3
+++ b/doc/pcre2_compile_context_create.3
@@ -1,4 +1,4 @@
-.TH PCRE2_COMPILE_CONTEXT_CREATE 3 "25 October 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_COMPILE_CONTEXT_CREATE 3 "25 October 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_compile_context_free.3 b/doc/pcre2_compile_context_free.3
index d51fc9d..75d3585 100644
--- a/doc/pcre2_compile_context_free.3
+++ b/doc/pcre2_compile_context_free.3
@@ -1,4 +1,4 @@
-.TH PCRE2_COMPILE_CONTEXT_FREE 3 "28 June 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_COMPILE_CONTEXT_FREE 3 "28 June 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_config.3 b/doc/pcre2_config.3
index 785bd00..2414297 100644
--- a/doc/pcre2_config.3
+++ b/doc/pcre2_config.3
@@ -1,4 +1,4 @@
-.TH PCRE2_CONFIG 3 "03 September 2025" "PCRE2 10.48-RC1"
+.TH PCRE2_CONFIG 3 "03 September 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_convert_context_copy.3 b/doc/pcre2_convert_context_copy.3
index 2c9e78b..0c5178a 100644
--- a/doc/pcre2_convert_context_copy.3
+++ b/doc/pcre2_convert_context_copy.3
@@ -1,4 +1,4 @@
-.TH PCRE2_CONVERT_CONTEXT_COPY 3 "12 July 2017" "PCRE2 10.48-RC1"
+.TH PCRE2_CONVERT_CONTEXT_COPY 3 "12 July 2017" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_convert_context_create.3 b/doc/pcre2_convert_context_create.3
index 7a55894..16d42ee 100644
--- a/doc/pcre2_convert_context_create.3
+++ b/doc/pcre2_convert_context_create.3
@@ -1,4 +1,4 @@
-.TH PCRE2_CONVERT_CONTEXT_CREATE 3 "12 July 2017" "PCRE2 10.48-RC1"
+.TH PCRE2_CONVERT_CONTEXT_CREATE 3 "12 July 2017" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_convert_context_free.3 b/doc/pcre2_convert_context_free.3
index 874982b..5918645 100644
--- a/doc/pcre2_convert_context_free.3
+++ b/doc/pcre2_convert_context_free.3
@@ -1,4 +1,4 @@
-.TH PCRE2_CONVERT_CONTEXT_FREE 3 "13 August 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_CONVERT_CONTEXT_FREE 3 "13 August 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_converted_pattern_free.3 b/doc/pcre2_converted_pattern_free.3
index b195236..d955f79 100644
--- a/doc/pcre2_converted_pattern_free.3
+++ b/doc/pcre2_converted_pattern_free.3
@@ -1,4 +1,4 @@
-.TH PCRE2_CONVERTED_PATTERN_FREE 3 "13 August 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_CONVERTED_PATTERN_FREE 3 "13 August 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_dfa_match.3 b/doc/pcre2_dfa_match.3
index f6ee613..e5de75f 100644
--- a/doc/pcre2_dfa_match.3
+++ b/doc/pcre2_dfa_match.3
@@ -1,4 +1,4 @@
-.TH PCRE2_DFA_MATCH 3 "31 August 2021" "PCRE2 10.48-RC1"
+.TH PCRE2_DFA_MATCH 3 "31 August 2021" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_general_context_copy.3 b/doc/pcre2_general_context_copy.3
index 0de6743..3993cd2 100644
--- a/doc/pcre2_general_context_copy.3
+++ b/doc/pcre2_general_context_copy.3
@@ -1,4 +1,4 @@
-.TH PCRE2_GENERAL_CONTEXT_COPY 3 "25 October 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_GENERAL_CONTEXT_COPY 3 "25 October 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_general_context_create.3 b/doc/pcre2_general_context_create.3
index d35dfa2..cc85e45 100644
--- a/doc/pcre2_general_context_create.3
+++ b/doc/pcre2_general_context_create.3
@@ -1,4 +1,4 @@
-.TH PCRE2_GENERAL_CONTEXT_CREATE 3 "23 January 2023" "PCRE2 10.48-RC1"
+.TH PCRE2_GENERAL_CONTEXT_CREATE 3 "23 January 2023" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_general_context_free.3 b/doc/pcre2_general_context_free.3
index b056780..8069c65 100644
--- a/doc/pcre2_general_context_free.3
+++ b/doc/pcre2_general_context_free.3
@@ -1,4 +1,4 @@
-.TH PCRE2_GENERAL_CONTEXT_FREE 3 "28 June 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_GENERAL_CONTEXT_FREE 3 "28 June 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_get_error_message.3 b/doc/pcre2_get_error_message.3
index d7b6657..7d87341 100644
--- a/doc/pcre2_get_error_message.3
+++ b/doc/pcre2_get_error_message.3
@@ -1,4 +1,4 @@
-.TH PCRE2_GET_ERROR_MESSAGE 3 "24 March 2017" "PCRE2 10.48-RC1"
+.TH PCRE2_GET_ERROR_MESSAGE 3 "24 March 2017" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_get_mark.3 b/doc/pcre2_get_mark.3
index 4ead97a..4e870ae 100644
--- a/doc/pcre2_get_mark.3
+++ b/doc/pcre2_get_mark.3
@@ -1,4 +1,4 @@
-.TH PCRE2_GET_MARK 3 "13 January 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_GET_MARK 3 "13 January 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_get_match_data_heapframes_size.3 b/doc/pcre2_get_match_data_heapframes_size.3
index b10e663..33f016e 100644
--- a/doc/pcre2_get_match_data_heapframes_size.3
+++ b/doc/pcre2_get_match_data_heapframes_size.3
@@ -1,4 +1,4 @@
-.TH PCRE2_GET_MATCH_DATA_HEAPFRAMES_SIZE 3 "18 January 2023" "PCRE2 10.48-RC1"
+.TH PCRE2_GET_MATCH_DATA_HEAPFRAMES_SIZE 3 "18 January 2023" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_get_match_data_size.3 b/doc/pcre2_get_match_data_size.3
index e7940b5..5216e99 100644
--- a/doc/pcre2_get_match_data_size.3
+++ b/doc/pcre2_get_match_data_size.3
@@ -1,4 +1,4 @@
-.TH PCRE2_GET_MATCH_DATA_SIZE 3 "17 October 2019" "PCRE2 10.48-RC1"
+.TH PCRE2_GET_MATCH_DATA_SIZE 3 "17 October 2019" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_get_ovector_count.3 b/doc/pcre2_get_ovector_count.3
index b6ef0e6..803d39e 100644
--- a/doc/pcre2_get_ovector_count.3
+++ b/doc/pcre2_get_ovector_count.3
@@ -1,4 +1,4 @@
-.TH PCRE2_GET_OVECTOR_COUNT 3 "25 October 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_GET_OVECTOR_COUNT 3 "25 October 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_get_ovector_pointer.3 b/doc/pcre2_get_ovector_pointer.3
index 5a0d168..bc42d3d 100644
--- a/doc/pcre2_get_ovector_pointer.3
+++ b/doc/pcre2_get_ovector_pointer.3
@@ -1,4 +1,4 @@
-.TH PCRE2_GET_OVECTOR_POINTER 3 "25 October 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_GET_OVECTOR_POINTER 3 "25 October 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_get_startchar.3 b/doc/pcre2_get_startchar.3
index bd1bf16..40a8ba6 100644
--- a/doc/pcre2_get_startchar.3
+++ b/doc/pcre2_get_startchar.3
@@ -1,4 +1,4 @@
-.TH PCRE2_GET_STARTCHAR 3 "25 October 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_GET_STARTCHAR 3 "25 October 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_jit_compile.3 b/doc/pcre2_jit_compile.3
index 410e2d2..bc95717 100644
--- a/doc/pcre2_jit_compile.3
+++ b/doc/pcre2_jit_compile.3
@@ -1,4 +1,4 @@
-.TH PCRE2_JIT_COMPILE 3 "22 August 2024" "PCRE2 10.48-RC1"
+.TH PCRE2_JIT_COMPILE 3 "22 August 2024" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_jit_free_unused_memory.3 b/doc/pcre2_jit_free_unused_memory.3
index ec7ea36..c0318da 100644
--- a/doc/pcre2_jit_free_unused_memory.3
+++ b/doc/pcre2_jit_free_unused_memory.3
@@ -1,4 +1,4 @@
-.TH PCRE2_JIT_FREE_UNUSED_MEMORY 3 "24 April 2020" "PCRE2 10.48-RC1"
+.TH PCRE2_JIT_FREE_UNUSED_MEMORY 3 "24 April 2020" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_jit_match.3 b/doc/pcre2_jit_match.3
index e82c129..5cc914b 100644
--- a/doc/pcre2_jit_match.3
+++ b/doc/pcre2_jit_match.3
@@ -1,4 +1,4 @@
-.TH PCRE2_JIT_MATCH 3 "20 January 2023" "PCRE2 10.48-RC1"
+.TH PCRE2_JIT_MATCH 3 "20 January 2023" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_jit_stack_assign.3 b/doc/pcre2_jit_stack_assign.3
index 763c8b5..7605632 100644
--- a/doc/pcre2_jit_stack_assign.3
+++ b/doc/pcre2_jit_stack_assign.3
@@ -1,4 +1,4 @@
-.TH PCRE2_JIT_STACK_ASSIGN 3 "13 August 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_JIT_STACK_ASSIGN 3 "13 August 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_jit_stack_create.3 b/doc/pcre2_jit_stack_create.3
index 055bb9d..318d850 100644
--- a/doc/pcre2_jit_stack_create.3
+++ b/doc/pcre2_jit_stack_create.3
@@ -1,4 +1,4 @@
-.TH PCRE2_JIT_STACK_CREATE 3 "23 January 2023" "PCRE2 10.48-RC1"
+.TH PCRE2_JIT_STACK_CREATE 3 "23 January 2023" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_jit_stack_free.3 b/doc/pcre2_jit_stack_free.3
index d8fb298..bd0c6ea 100644
--- a/doc/pcre2_jit_stack_free.3
+++ b/doc/pcre2_jit_stack_free.3
@@ -1,4 +1,4 @@
-.TH PCRE2_JIT_STACK_FREE 3 "26 February 2025" "PCRE2 10.48-RC1"
+.TH PCRE2_JIT_STACK_FREE 3 "26 February 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_maketables.3 b/doc/pcre2_maketables.3
index 1191842..7efba74 100644
--- a/doc/pcre2_maketables.3
+++ b/doc/pcre2_maketables.3
@@ -1,4 +1,4 @@
-.TH PCRE2_MAKETABLES 3 "26 February 2025" "PCRE2 10.48-RC1"
+.TH PCRE2_MAKETABLES 3 "26 February 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_maketables_free.3 b/doc/pcre2_maketables_free.3
index 819a6b6..9031c99 100644
--- a/doc/pcre2_maketables_free.3
+++ b/doc/pcre2_maketables_free.3
@@ -1,4 +1,4 @@
-.TH PCRE2_MAKETABLES_FREE 3 "03 September 2019" "PCRE2 10.48-RC1"
+.TH PCRE2_MAKETABLES_FREE 3 "03 September 2019" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_match.3 b/doc/pcre2_match.3
index 69c31f1..4fe04ff 100644
--- a/doc/pcre2_match.3
+++ b/doc/pcre2_match.3
@@ -1,4 +1,4 @@
-.TH PCRE2_MATCH 3 "27 January 2024" "PCRE2 10.48-RC1"
+.TH PCRE2_MATCH 3 "27 January 2024" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_match_context_copy.3 b/doc/pcre2_match_context_copy.3
index d35153f..381391f 100644
--- a/doc/pcre2_match_context_copy.3
+++ b/doc/pcre2_match_context_copy.3
@@ -1,4 +1,4 @@
-.TH PCRE2_MATCH_CONTEXT_COPY 3 "25 October 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_MATCH_CONTEXT_COPY 3 "25 October 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_match_context_create.3 b/doc/pcre2_match_context_create.3
index e616453..94887bb 100644
--- a/doc/pcre2_match_context_create.3
+++ b/doc/pcre2_match_context_create.3
@@ -1,4 +1,4 @@
-.TH PCRE2_MATCH_CONTEXT_CREATE 3 "25 October 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_MATCH_CONTEXT_CREATE 3 "25 October 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_match_context_free.3 b/doc/pcre2_match_context_free.3
index 93844b0..199f7e1 100644
--- a/doc/pcre2_match_context_free.3
+++ b/doc/pcre2_match_context_free.3
@@ -1,4 +1,4 @@
-.TH PCRE2_MATCH_CONTEXT_FREE 3 "28 June 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_MATCH_CONTEXT_FREE 3 "28 June 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_match_data_create.3 b/doc/pcre2_match_data_create.3
index ca8aad6..068cefe 100644
--- a/doc/pcre2_match_data_create.3
+++ b/doc/pcre2_match_data_create.3
@@ -1,4 +1,4 @@
-.TH PCRE2_MATCH_DATA_CREATE 3 "28 August 2021" "PCRE2 10.48-RC1"
+.TH PCRE2_MATCH_DATA_CREATE 3 "28 August 2021" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_match_data_create_from_pattern.3 b/doc/pcre2_match_data_create_from_pattern.3
index c9d9495..10eb594 100644
--- a/doc/pcre2_match_data_create_from_pattern.3
+++ b/doc/pcre2_match_data_create_from_pattern.3
@@ -1,4 +1,4 @@
-.TH PCRE2_MATCH_DATA_CREATE_FROM_PATTERN 3 "11 August 2025" "PCRE2 10.48-RC1"
+.TH PCRE2_MATCH_DATA_CREATE_FROM_PATTERN 3 "11 August 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_match_data_free.3 b/doc/pcre2_match_data_free.3
index 9cf7f5c..6e2d8dc 100644
--- a/doc/pcre2_match_data_free.3
+++ b/doc/pcre2_match_data_free.3
@@ -1,4 +1,4 @@
-.TH PCRE2_MATCH_DATA_FREE 3 "16 August 2023" "PCRE2 10.48-RC1"
+.TH PCRE2_MATCH_DATA_FREE 3 "16 August 2023" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_next_match.3 b/doc/pcre2_next_match.3
index b38eba3..44da3d2 100644
--- a/doc/pcre2_next_match.3
+++ b/doc/pcre2_next_match.3
@@ -1,4 +1,4 @@
-.TH PCRE2_NEXT_MATCH 3 "24 March 2025" "PCRE2 10.48-RC1"
+.TH PCRE2_NEXT_MATCH 3 "24 March 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_pattern_convert.3 b/doc/pcre2_pattern_convert.3
index 41f45e7..d6f3c68 100644
--- a/doc/pcre2_pattern_convert.3
+++ b/doc/pcre2_pattern_convert.3
@@ -1,4 +1,4 @@
-.TH PCRE2_PATTERN_CONVERT 3 "12 July 2017" "PCRE2 10.48-RC1"
+.TH PCRE2_PATTERN_CONVERT 3 "12 July 2017" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_pattern_info.3 b/doc/pcre2_pattern_info.3
index c40328e..51d40f3 100644
--- a/doc/pcre2_pattern_info.3
+++ b/doc/pcre2_pattern_info.3
@@ -1,4 +1,4 @@
-.TH PCRE2_PATTERN_INFO 3 "14 February 2019" "PCRE2 10.48-RC1"
+.TH PCRE2_PATTERN_INFO 3 "14 February 2019" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_serialize_decode.3 b/doc/pcre2_serialize_decode.3
index 2a9e401..9e4af0c 100644
--- a/doc/pcre2_serialize_decode.3
+++ b/doc/pcre2_serialize_decode.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SERIALIZE_DECODE 3 "22 April 2022" "PCRE2 10.48-RC1"
+.TH PCRE2_SERIALIZE_DECODE 3 "22 April 2022" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_serialize_encode.3 b/doc/pcre2_serialize_encode.3
index 0fff174..e5d8ae6 100644
--- a/doc/pcre2_serialize_encode.3
+++ b/doc/pcre2_serialize_encode.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SERIALIZE_ENCODE 3 "13 August 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_SERIALIZE_ENCODE 3 "13 August 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_serialize_free.3 b/doc/pcre2_serialize_free.3
index ec1d68d..545d865 100644
--- a/doc/pcre2_serialize_free.3
+++ b/doc/pcre2_serialize_free.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SERIALIZE_FREE 3 "13 August 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_SERIALIZE_FREE 3 "13 August 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_serialize_get_number_of_codes.3 b/doc/pcre2_serialize_get_number_of_codes.3
index 35329e9..ea76daa 100644
--- a/doc/pcre2_serialize_get_number_of_codes.3
+++ b/doc/pcre2_serialize_get_number_of_codes.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SERIALIZE_GET_NUMBER_OF_CODES 3 "13 August 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_SERIALIZE_GET_NUMBER_OF_CODES 3 "13 August 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_bsr.3 b/doc/pcre2_set_bsr.3
index 71e7756..1d2b0de 100644
--- a/doc/pcre2_set_bsr.3
+++ b/doc/pcre2_set_bsr.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_BSR 3 "25 October 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_BSR 3 "25 October 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_callout.3 b/doc/pcre2_set_callout.3
index 4d2090d..7b20d9f 100644
--- a/doc/pcre2_set_callout.3
+++ b/doc/pcre2_set_callout.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_CALLOUT 3 "25 March 2017" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_CALLOUT 3 "25 March 2017" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_character_tables.3 b/doc/pcre2_set_character_tables.3
index 4e17399..a57041c 100644
--- a/doc/pcre2_set_character_tables.3
+++ b/doc/pcre2_set_character_tables.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_CHARACTER_TABLES 3 "15 April 2020" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_CHARACTER_TABLES 3 "15 April 2020" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_compile_extra_options.3 b/doc/pcre2_set_compile_extra_options.3
index d1d414b..d1eb8d3 100644
--- a/doc/pcre2_set_compile_extra_options.3
+++ b/doc/pcre2_set_compile_extra_options.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_COMPILE_EXTRA_OPTIONS 3 "14 October 2024" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_COMPILE_EXTRA_OPTIONS 3 "14 October 2024" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_compile_recursion_guard.3 b/doc/pcre2_set_compile_recursion_guard.3
index de03c25..a6c80be 100644
--- a/doc/pcre2_set_compile_recursion_guard.3
+++ b/doc/pcre2_set_compile_recursion_guard.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_COMPILE_RECURSION_GUARD 3 "26 November 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_COMPILE_RECURSION_GUARD 3 "26 November 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_depth_limit.3 b/doc/pcre2_set_depth_limit.3
index 7203f1c..59857b8 100644
--- a/doc/pcre2_set_depth_limit.3
+++ b/doc/pcre2_set_depth_limit.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_DEPTH_LIMIT 3 "25 March 2017" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_DEPTH_LIMIT 3 "25 March 2017" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_glob_escape.3 b/doc/pcre2_set_glob_escape.3
index 93cbcd4..73ef5c9 100644
--- a/doc/pcre2_set_glob_escape.3
+++ b/doc/pcre2_set_glob_escape.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_GLOB_ESCAPE 3 "12 July 2017" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_GLOB_ESCAPE 3 "12 July 2017" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_glob_separator.3 b/doc/pcre2_set_glob_separator.3
index bafbe88..cba2042 100644
--- a/doc/pcre2_set_glob_separator.3
+++ b/doc/pcre2_set_glob_separator.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_GLOB_SEPARATOR 3 "17 June 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_GLOB_SEPARATOR 3 "17 June 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_heap_limit.3 b/doc/pcre2_set_heap_limit.3
index 5cfc714..c5fa2dd 100644
--- a/doc/pcre2_set_heap_limit.3
+++ b/doc/pcre2_set_heap_limit.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_HEAP_LIMIT 3 "17 June 2018" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_HEAP_LIMIT 3 "17 June 2018" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_match_limit.3 b/doc/pcre2_set_match_limit.3
index 5e809ad..4c1da55 100644
--- a/doc/pcre2_set_match_limit.3
+++ b/doc/pcre2_set_match_limit.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_MATCH_LIMIT 3 "25 October 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_MATCH_LIMIT 3 "25 October 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_max_pattern_compiled_length.3 b/doc/pcre2_set_max_pattern_compiled_length.3
index d931821..93c389b 100644
--- a/doc/pcre2_set_max_pattern_compiled_length.3
+++ b/doc/pcre2_set_max_pattern_compiled_length.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_MAX_PATTERN_COMPILED_LENGTH 3 "09 June 2024" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_MAX_PATTERN_COMPILED_LENGTH 3 "09 June 2024" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_max_pattern_length.3 b/doc/pcre2_set_max_pattern_length.3
index be5b388..3946e91 100644
--- a/doc/pcre2_set_max_pattern_length.3
+++ b/doc/pcre2_set_max_pattern_length.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_MAX_PATTERN_LENGTH 3 "05 October 2016" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_MAX_PATTERN_LENGTH 3 "05 October 2016" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_max_varlookbehind.3 b/doc/pcre2_set_max_varlookbehind.3
index 98d9f91..a3aa86d 100644
--- a/doc/pcre2_set_max_varlookbehind.3
+++ b/doc/pcre2_set_max_varlookbehind.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_NEWLINE 3 "11 August 2023" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_NEWLINE 3 "11 August 2023" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_newline.3 b/doc/pcre2_set_newline.3
index f227138..5668767 100644
--- a/doc/pcre2_set_newline.3
+++ b/doc/pcre2_set_newline.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_NEWLINE 3 "19 July 2017" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_NEWLINE 3 "19 July 2017" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_offset_limit.3 b/doc/pcre2_set_offset_limit.3
index 19476c0..02ebb33 100644
--- a/doc/pcre2_set_offset_limit.3
+++ b/doc/pcre2_set_offset_limit.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_OFFSET_LIMIT 3 "22 September 2015" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_OFFSET_LIMIT 3 "22 September 2015" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_optimize.3 b/doc/pcre2_set_optimize.3
index 12ae23a..181f268 100644
--- a/doc/pcre2_set_optimize.3
+++ b/doc/pcre2_set_optimize.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_OPTIMIZE 3 "22 September 2024" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_OPTIMIZE 3 "22 September 2024" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_parens_nest_limit.3 b/doc/pcre2_set_parens_nest_limit.3
index 3103ffd..910bd5c 100644
--- a/doc/pcre2_set_parens_nest_limit.3
+++ b/doc/pcre2_set_parens_nest_limit.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_PARENS_NEST_LIMIT 3 "25 October 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_PARENS_NEST_LIMIT 3 "25 October 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_recursion_limit.3 b/doc/pcre2_set_recursion_limit.3
index c5e5817..8138dd5 100644
--- a/doc/pcre2_set_recursion_limit.3
+++ b/doc/pcre2_set_recursion_limit.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_RECURSION_LIMIT 3 "19 July 2017" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_RECURSION_LIMIT 3 "19 July 2017" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_recursion_memory_management.3 b/doc/pcre2_set_recursion_memory_management.3
index 2de1ac6..a0bb4af 100644
--- a/doc/pcre2_set_recursion_memory_management.3
+++ b/doc/pcre2_set_recursion_memory_management.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_RECURSION_MEMORY_MANAGEMENT 3 "23 January 2023" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_RECURSION_MEMORY_MANAGEMENT 3 "23 January 2023" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_substitute_callout.3 b/doc/pcre2_set_substitute_callout.3
index 819e0a1..80917f0 100644
--- a/doc/pcre2_set_substitute_callout.3
+++ b/doc/pcre2_set_substitute_callout.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_SUBSTITUTE_CALLOUT 3 "04 October 2024" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_SUBSTITUTE_CALLOUT 3 "04 October 2024" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_set_substitute_case_callout.3 b/doc/pcre2_set_substitute_case_callout.3
index 1ede07b..b52fbe8 100644
--- a/doc/pcre2_set_substitute_case_callout.3
+++ b/doc/pcre2_set_substitute_case_callout.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SET_SUBSTITUTE_CASE_CALLOUT 3 "26 December 2024" "PCRE2 10.48-RC1"
+.TH PCRE2_SET_SUBSTITUTE_CASE_CALLOUT 3 "26 December 2024" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_substitute.3 b/doc/pcre2_substitute.3
index 666a187..1bc8aa9 100644
--- a/doc/pcre2_substitute.3
+++ b/doc/pcre2_substitute.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTITUTE 3 "03 October 2025" "PCRE2 10.48-RC1"
+.TH PCRE2_SUBSTITUTE 3 "03 October 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_substring_copy_byname.3 b/doc/pcre2_substring_copy_byname.3
index 24d986b..1fade54 100644
--- a/doc/pcre2_substring_copy_byname.3
+++ b/doc/pcre2_substring_copy_byname.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTRING_COPY_BYNAME 3 "19 December 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_SUBSTRING_COPY_BYNAME 3 "19 December 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_substring_copy_bynumber.3 b/doc/pcre2_substring_copy_bynumber.3
index f8fcb7a..11f3777 100644
--- a/doc/pcre2_substring_copy_bynumber.3
+++ b/doc/pcre2_substring_copy_bynumber.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTRING_COPY_BYNUMBER 3 "13 December 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_SUBSTRING_COPY_BYNUMBER 3 "13 December 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_substring_free.3 b/doc/pcre2_substring_free.3
index 10c5377..58ae037 100644
--- a/doc/pcre2_substring_free.3
+++ b/doc/pcre2_substring_free.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTRING_FREE 3 "26 February 2025" "PCRE2 10.48-RC1"
+.TH PCRE2_SUBSTRING_FREE 3 "26 February 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_substring_get_byname.3 b/doc/pcre2_substring_get_byname.3
index ccdddd9..a841403 100644
--- a/doc/pcre2_substring_get_byname.3
+++ b/doc/pcre2_substring_get_byname.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTRING_GET_BYNAME 3 "19 December 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_SUBSTRING_GET_BYNAME 3 "19 December 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_substring_get_bynumber.3 b/doc/pcre2_substring_get_bynumber.3
index d7fd8be..1efe1e2 100644
--- a/doc/pcre2_substring_get_bynumber.3
+++ b/doc/pcre2_substring_get_bynumber.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTRING_GET_BYNUMBER 3 "13 December 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_SUBSTRING_GET_BYNUMBER 3 "13 December 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_substring_length_byname.3 b/doc/pcre2_substring_length_byname.3
index cbb4428..1c3815f 100644
--- a/doc/pcre2_substring_length_byname.3
+++ b/doc/pcre2_substring_length_byname.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTRING_LENGTH_BYNAME 3 "26 September 2025" "PCRE2 10.48-RC1"
+.TH PCRE2_SUBSTRING_LENGTH_BYNAME 3 "26 September 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_substring_length_bynumber.3 b/doc/pcre2_substring_length_bynumber.3
index 1503957..0c81f55 100644
--- a/doc/pcre2_substring_length_bynumber.3
+++ b/doc/pcre2_substring_length_bynumber.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTRING_LENGTH_BYNUMBER 3 "22 December 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_SUBSTRING_LENGTH_BYNUMBER 3 "22 December 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_substring_list_free.3 b/doc/pcre2_substring_list_free.3
index c31e5e5..a17712e 100644
--- a/doc/pcre2_substring_list_free.3
+++ b/doc/pcre2_substring_list_free.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTRING_LIST_FREE 3 "26 February 2025" "PCRE2 10.48-RC1"
+.TH PCRE2_SUBSTRING_LIST_FREE 3 "26 February 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_substring_list_get.3 b/doc/pcre2_substring_list_get.3
index 9a5db54..b7868d0 100644
--- a/doc/pcre2_substring_list_get.3
+++ b/doc/pcre2_substring_list_get.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTRING_LIST_GET 3 "21 October 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_SUBSTRING_LIST_GET 3 "21 October 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_substring_nametable_scan.3 b/doc/pcre2_substring_nametable_scan.3
index 0898b0b..849d827 100644
--- a/doc/pcre2_substring_nametable_scan.3
+++ b/doc/pcre2_substring_nametable_scan.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTRING_NAMETABLE_SCAN 3 "06 February 2019" "PCRE2 10.48-RC1"
+.TH PCRE2_SUBSTRING_NAMETABLE_SCAN 3 "06 February 2019" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2_substring_number_from_name.3 b/doc/pcre2_substring_number_from_name.3
index e5aa7f9..bbd1400 100644
--- a/doc/pcre2_substring_number_from_name.3
+++ b/doc/pcre2_substring_number_from_name.3
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTRING_NUMBER_FROM_NAME 3 "03 November 2014" "PCRE2 10.48-RC1"
+.TH PCRE2_SUBSTRING_NUMBER_FROM_NAME 3 "03 November 2014" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2api.3 b/doc/pcre2api.3
index f3df177..8d49818 100644
--- a/doc/pcre2api.3
+++ b/doc/pcre2api.3
@@ -1,4 +1,4 @@
-.TH PCRE2API 3 "08 December 2025" "PCRE2 10.48-RC1"
+.TH PCRE2API 3 "08 December 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.sp
diff --git a/doc/pcre2build.3 b/doc/pcre2build.3
index fa12121..1b9b712 100644
--- a/doc/pcre2build.3
+++ b/doc/pcre2build.3
@@ -1,4 +1,4 @@
-.TH PCRE2BUILD 3 "17 October 2025" "PCRE2 10.48-RC1"
+.TH PCRE2BUILD 3 "17 October 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.
diff --git a/doc/pcre2callout.3 b/doc/pcre2callout.3
index f1bacb8..a00ecf5 100644
--- a/doc/pcre2callout.3
+++ b/doc/pcre2callout.3
@@ -1,4 +1,4 @@
-.TH PCRE2CALLOUT 3 "26 February 2025" "PCRE2 10.48-RC1"
+.TH PCRE2CALLOUT 3 "26 February 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
diff --git a/doc/pcre2compat.3 b/doc/pcre2compat.3
index 3ea2881..9435a9d 100644
--- a/doc/pcre2compat.3
+++ b/doc/pcre2compat.3
@@ -1,4 +1,4 @@
-.TH PCRE2COMPAT 3 "02 June 2025" "PCRE2 10.48-RC1"
+.TH PCRE2COMPAT 3 "02 June 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "DIFFERENCES BETWEEN PCRE2 AND PERL"
diff --git a/doc/pcre2convert.3 b/doc/pcre2convert.3
index ac1495b..d227f47 100644
--- a/doc/pcre2convert.3
+++ b/doc/pcre2convert.3
@@ -1,4 +1,4 @@
-.TH PCRE2CONVERT 3 "14 November 2023" "PCRE2 10.48-RC1"
+.TH PCRE2CONVERT 3 "14 November 2023" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "EXPERIMENTAL PATTERN CONVERSION FUNCTIONS"
diff --git a/doc/pcre2demo.3 b/doc/pcre2demo.3
index 2d258af..b4a360f 100644
--- a/doc/pcre2demo.3
+++ b/doc/pcre2demo.3
@@ -1,4 +1,4 @@
-.TH PCRE2DEMO 3 "24 March 2025" "PCRE2 10.48-RC1"
+.TH PCRE2DEMO 3 "24 March 2025" "PCRE2 10.48"
.\"AUTOMATICALLY GENERATED BY UpdateAlways - do not EDIT!
.SH NAME
PCRE2DEMO - A demonstration C program for PCRE2
diff --git a/doc/pcre2grep.1 b/doc/pcre2grep.1
index d7104bb..ab57cad 100644
--- a/doc/pcre2grep.1
+++ b/doc/pcre2grep.1
@@ -1,4 +1,4 @@
-.TH PCRE2GREP 1 "24 January 2025" "PCRE2 10.48-RC1"
+.TH PCRE2GREP 1 "24 January 2025" "PCRE2 10.48"
.SH NAME
pcre2grep - a grep with Perl-compatible regular expressions.
.SH SYNOPSIS
diff --git a/doc/pcre2grep.txt b/doc/pcre2grep.txt
index 4842755..99f14ab 100644
--- a/doc/pcre2grep.txt
+++ b/doc/pcre2grep.txt
@@ -1103,4 +1103,4 @@ REVISION
Copyright (c) 1997-2023 University of Cambridge.
-PCRE2 10.48-RC1 24 January 2025 PCRE2GREP(1)
+PCRE2 10.48 24 January 2025 PCRE2GREP(1)
diff --git a/doc/pcre2jit.3 b/doc/pcre2jit.3
index 23dcb91..947cd41 100644
--- a/doc/pcre2jit.3
+++ b/doc/pcre2jit.3
@@ -1,4 +1,4 @@
-.TH PCRE2JIT 3 "08 August 2026" "PCRE2 10.48-RC1"
+.TH PCRE2JIT 3 "08 August 2026" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "PCRE2 JUST-IN-TIME COMPILER SUPPORT"
diff --git a/doc/pcre2limits.3 b/doc/pcre2limits.3
index 9b8e6a6..03c1ee9 100644
--- a/doc/pcre2limits.3
+++ b/doc/pcre2limits.3
@@ -1,4 +1,4 @@
-.TH PCRE2LIMITS 3 "03 September 2025" "PCRE2 10.48-RC1"
+.TH PCRE2LIMITS 3 "03 September 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "SIZE AND OTHER LIMITATIONS"
diff --git a/doc/pcre2matching.3 b/doc/pcre2matching.3
index 23f6eb4..7d5b04b 100644
--- a/doc/pcre2matching.3
+++ b/doc/pcre2matching.3
@@ -1,4 +1,4 @@
-.TH PCRE2MATCHING 3 "22 February 2025" "PCRE2 10.48-RC1"
+.TH PCRE2MATCHING 3 "22 February 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "PCRE2 MATCHING ALGORITHMS"
diff --git a/doc/pcre2partial.3 b/doc/pcre2partial.3
index b55630e..2b7ad09 100644
--- a/doc/pcre2partial.3
+++ b/doc/pcre2partial.3
@@ -1,4 +1,4 @@
-.TH PCRE2PARTIAL 3 "16 August 2026" "PCRE2 10.48-RC1"
+.TH PCRE2PARTIAL 3 "16 August 2026" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "PARTIAL MATCHING IN PCRE2"
diff --git a/doc/pcre2pattern.3 b/doc/pcre2pattern.3
index 489adc3..ad946b4 100644
--- a/doc/pcre2pattern.3
+++ b/doc/pcre2pattern.3
@@ -1,4 +1,4 @@
-.TH PCRE2PATTERN 3 "25 October 2025" "PCRE2 10.48-RC1"
+.TH PCRE2PATTERN 3 "25 October 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "PCRE2 REGULAR EXPRESSION DETAILS"
diff --git a/doc/pcre2perform.3 b/doc/pcre2perform.3
index 1a8c2b5..bec85fe 100644
--- a/doc/pcre2perform.3
+++ b/doc/pcre2perform.3
@@ -1,4 +1,4 @@
-.TH PCRE2PERFORM 3 "06 December 2022" "PCRE2 10.48-RC1"
+.TH PCRE2PERFORM 3 "06 December 2022" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "PCRE2 PERFORMANCE"
diff --git a/doc/pcre2posix.3 b/doc/pcre2posix.3
index 59cfb77..e788bd4 100644
--- a/doc/pcre2posix.3
+++ b/doc/pcre2posix.3
@@ -1,4 +1,4 @@
-.TH PCRE2POSIX 3 "27 November 2024" "PCRE2 10.48-RC1"
+.TH PCRE2POSIX 3 "27 November 2024" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "SYNOPSIS"
diff --git a/doc/pcre2sample.3 b/doc/pcre2sample.3
index 84a8c87..f931df2 100644
--- a/doc/pcre2sample.3
+++ b/doc/pcre2sample.3
@@ -1,4 +1,4 @@
-.TH PCRE2SAMPLE 3 "28 February 2025" "PCRE2 10.48-RC1"
+.TH PCRE2SAMPLE 3 "28 February 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "PCRE2 SAMPLE PROGRAM"
diff --git a/doc/pcre2serialize.3 b/doc/pcre2serialize.3
index 758e887..46e75a7 100644
--- a/doc/pcre2serialize.3
+++ b/doc/pcre2serialize.3
@@ -1,4 +1,4 @@
-.TH PCRE2SERIALIZE 3 "19 January 2024" "PCRE2 10.48-RC1"
+.TH PCRE2SERIALIZE 3 "19 January 2024" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "SAVING AND RE-USING PRECOMPILED PCRE2 PATTERNS"
diff --git a/doc/pcre2syntax.3 b/doc/pcre2syntax.3
index b9f23df..c3a68bd 100644
--- a/doc/pcre2syntax.3
+++ b/doc/pcre2syntax.3
@@ -1,4 +1,4 @@
-.TH PCRE2SYNTAX 3 "14 October 2025" "PCRE2 10.48-RC1"
+.TH PCRE2SYNTAX 3 "14 October 2025" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "PCRE2 REGULAR EXPRESSION SYNTAX SUMMARY"
diff --git a/doc/pcre2test.1 b/doc/pcre2test.1
index f66af14..405578d 100644
--- a/doc/pcre2test.1
+++ b/doc/pcre2test.1
@@ -1,4 +1,4 @@
-.TH PCRE2TEST 1 "22 August 2026" "PCRE2 10.48-RC1"
+.TH PCRE2TEST 1 "22 August 2026" "PCRE2 10.48"
.SH NAME
pcre2test - a program for testing Perl-compatible regular expressions.
.SH SYNOPSIS
diff --git a/doc/pcre2test.txt b/doc/pcre2test.txt
index 5dc42f1..e0e8554 100644
--- a/doc/pcre2test.txt
+++ b/doc/pcre2test.txt
@@ -2104,4 +2104,4 @@ REVISION
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.48-RC1 22 August 2026 PCRE2TEST(1)
+PCRE2 10.48 22 August 2026 PCRE2TEST(1)
diff --git a/doc/pcre2unicode.3 b/doc/pcre2unicode.3
index e6cda0a..c6bb26e 100644
--- a/doc/pcre2unicode.3
+++ b/doc/pcre2unicode.3
@@ -1,4 +1,4 @@
-.TH PCRE2UNICODE 3 "27 November 2024" "PCRE2 10.48-RC1"
+.TH PCRE2UNICODE 3 "27 November 2024" "PCRE2 10.48"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "UNICODE AND UTF SUPPORT"
diff --git a/patches/pcre2-10.37-Remove-real-POSIX.patch b/patches/pcre2-10.37-Remove-real-POSIX.patch
index 22b50c0..a5f9d44 100644
--- a/patches/pcre2-10.37-Remove-real-POSIX.patch
+++ b/patches/pcre2-10.37-Remove-real-POSIX.patch
@@ -4,10 +4,321 @@ Date: Tue Apr 27 08:36:47 2021 +0000
Remove real POSIX function names from the pcre2-posix library.
+diff --git a/ChangeLog b/ChangeLog
+index 5d64b35d..6bc766dc 100644
+--- a/ChangeLog
++++ b/ChangeLog
+@@ -11,13 +11,13 @@ with binary zeros. This is from Bugzilla #2681. Patch from Jeremie
+ Courreges-Anglas via Nam Nguyen. This fixes RunGrepTest for OpenBSD. Later:
+ it broke it for at least one version of Solaris, where tr can't handle binary
+ zeros. However, that system had /usr/xpg4/bin/tr installed, which works OK, so
+-RunGrepTest now checks for that command and use it if found.
++RunGrepTest now checks for that command and uses it if found.
+
+ 2. Compiling with gcc 10.2's -fanalyzer option showed up a hypothetical problem
+ with a NULL dereference. I don't think this case could ever occur in practice,
+ but I have put in a check in order to get rid of the compiler error.
+
+-3. An alternative patch for CMakeLists.txt because 10.36 # 4 breaks CMake on
++3. An alternative patch for CMakeLists.txt because 10.36 #4 breaks CMake on
+ Windows. Patch from email@cs-ware.de fixes bugzilla #2688.
+
+ 4. Two bugs related to over-large numbers have been fixed so the behaviour is
+@@ -44,6 +44,14 @@ recursions such as /(a\K.(?1)*)/ did not have this problem.
+ 7. Restore single character repetition optimization in JIT. Currently fewer
+ character repetitions are optimized than in 10.34.
+
++8. When the names of the functions in the POSIX wrapper were changed to
++pcre2_regcomp() etc. (see change 10.33 #4 below), functions with the original
++names were left in the library so that pre-compiled programs would still work.
++However, this has proved troublesome when programs link with several libraries,
++some of which use PCRE2 via the POSIX interface while others use a native POSIX
++library. For this reason, the POSIX function names are removed in this release.
++The macros in pcre2posix.h should ensure that re-compiling fixes any programs
++that haven't been compiled since before 10.33.
+
+
+ Version 10.36 04-December-2020
+diff --git a/doc/html/pcre2posix.html b/doc/html/pcre2posix.html
+index 20a2009b..c54860f9 100644
+--- a/doc/html/pcre2posix.html
++++ b/doc/html/pcre2posix.html
+@@ -68,11 +68,14 @@ application. Because the POSIX functions call the native ones, it is also
+ necessary to add -lpcre2-8.
+
+
+-Although they are not defined as protypes in pcre2posix.h, the library
+-does contain functions with the POSIX names regcomp() etc. These simply
+-pass their arguments to the PCRE2 functions. These functions are provided for
+-backwards compatibility with earlier versions of PCRE2, so that existing
+-programs do not have to be recompiled.
++Although they were not defined as protypes in pcre2posix.h, releases
++10.33 to 10.36 of the library contained functions with the POSIX names
++regcomp() etc. These simply passed their arguments to the PCRE2
++functions. These functions were provided for backwards compatibility with
++earlier versions of PCRE2, which had only POSIX names. However, this has proved
++troublesome in situations where a program links with several libraries, some of
++which use PCRE2's POSIX interface while others use the real POSIX functions.
++For this reason, the POSIX names have been removed since release 10.37.
+
+
+ Calling the header file pcre2posix.h avoids any conflict with other POSIX
+@@ -344,9 +347,9 @@ Cambridge, England.
+
+
REVISION
+
+-Last updated: 30 January 2019
++Last updated: 26 April 2021
+
+-Copyright © 1997-2019 University of Cambridge.
++Copyright © 1997-2021 University of Cambridge.
+
+
+ Return to the PCRE2 index page.
+diff --git a/doc/pcre2.txt b/doc/pcre2.txt
+index 365ecc49..61855f19 100644
+--- a/doc/pcre2.txt
++++ b/doc/pcre2.txt
+@@ -180,8 +180,8 @@ REVISION
+ Last updated: 17 September 2018
+ Copyright (c) 1997-2018 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2API(3) Library Functions Manual PCRE2API(3)
+
+
+@@ -3829,8 +3829,8 @@ REVISION
+ Last updated: 04 November 2020
+ Copyright (c) 1997-2020 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2BUILD(3) Library Functions Manual PCRE2BUILD(3)
+
+
+@@ -4423,8 +4423,8 @@ REVISION
+ Last updated: 20 March 2020
+ Copyright (c) 1997-2020 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2CALLOUT(3) Library Functions Manual PCRE2CALLOUT(3)
+
+
+@@ -4853,8 +4853,8 @@ REVISION
+ Last updated: 03 February 2019
+ Copyright (c) 1997-2019 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2COMPAT(3) Library Functions Manual PCRE2COMPAT(3)
+
+
+@@ -5066,8 +5066,8 @@ REVISION
+ Last updated: 06 October 2020
+ Copyright (c) 1997-2019 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2JIT(3) Library Functions Manual PCRE2JIT(3)
+
+
+@@ -5491,8 +5491,8 @@ REVISION
+ Last updated: 23 May 2019
+ Copyright (c) 1997-2019 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2LIMITS(3) Library Functions Manual PCRE2LIMITS(3)
+
+
+@@ -5561,8 +5561,8 @@ REVISION
+ Last updated: 02 February 2019
+ Copyright (c) 1997-2019 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2MATCHING(3) Library Functions Manual PCRE2MATCHING(3)
+
+
+@@ -5785,8 +5785,8 @@ REVISION
+ Last updated: 23 May 2019
+ Copyright (c) 1997-2019 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2PARTIAL(3) Library Functions Manual PCRE2PARTIAL(3)
+
+
+@@ -6165,8 +6165,8 @@ REVISION
+ Last updated: 04 September 2019
+ Copyright (c) 1997-2019 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2PATTERN(3) Library Functions Manual PCRE2PATTERN(3)
+
+
+@@ -9613,8 +9613,8 @@ REVISION
+ Last updated: 06 October 2020
+ Copyright (c) 1997-2020 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2PERFORM(3) Library Functions Manual PCRE2PERFORM(3)
+
+
+@@ -9848,8 +9848,8 @@ REVISION
+ Last updated: 03 February 2019
+ Copyright (c) 1997-2019 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2POSIX(3) Library Functions Manual PCRE2POSIX(3)
+
+
+@@ -9895,11 +9895,15 @@ DESCRIPTION
+ an application. Because the POSIX functions call the native ones, it is
+ also necessary to add -lpcre2-8.
+
+- Although they are not defined as protypes in pcre2posix.h, the library
+- does contain functions with the POSIX names regcomp() etc. These simply
+- pass their arguments to the PCRE2 functions. These functions are pro-
+- vided for backwards compatibility with earlier versions of PCRE2, so
+- that existing programs do not have to be recompiled.
++ Although they were not defined as protypes in pcre2posix.h, releases
++ 10.33 to 10.36 of the library contained functions with the POSIX names
++ regcomp() etc. These simply passed their arguments to the PCRE2 func-
++ tions. These functions were provided for backwards compatibility with
++ earlier versions of PCRE2, which had only POSIX names. However, this
++ has proved troublesome in situations where a program links with several
++ libraries, some of which use PCRE2's POSIX interface while others use
++ the real POSIX functions. For this reason, the POSIX names have been
++ removed since release 10.37.
+
+ Calling the header file pcre2posix.h avoids any conflict with other
+ POSIX libraries. It can, of course, be renamed or aliased as regex.h,
+@@ -10175,11 +10179,11 @@ AUTHOR
+
+ REVISION
+
+- Last updated: 30 January 2019
+- Copyright (c) 1997-2019 University of Cambridge.
++ Last updated: 26 April 2021
++ Copyright (c) 1997-2021 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2SAMPLE(3) Library Functions Manual PCRE2SAMPLE(3)
+
+
+@@ -10457,8 +10461,8 @@ REVISION
+ Last updated: 27 June 2018
+ Copyright (c) 1997-2018 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2SYNTAX(3) Library Functions Manual PCRE2SYNTAX(3)
+
+
+@@ -10973,8 +10977,8 @@ REVISION
+ Last updated: 28 December 2019
+ Copyright (c) 1997-2019 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+ PCRE2UNICODE(3) Library Functions Manual PCRE2UNICODE(3)
+
+
+@@ -11408,5 +11412,5 @@ REVISION
+ Last updated: 23 February 2020
+ Copyright (c) 1997-2020 University of Cambridge.
+ ------------------------------------------------------------------------------
+-
+-
++
++
+diff --git a/doc/pcre2posix.3 b/doc/pcre2posix.3
+index 35e68e2d..a470c8f9 100644
+--- a/doc/pcre2posix.3
++++ b/doc/pcre2posix.3
+@@ -1,4 +1,4 @@
+-.TH PCRE2POSIX 3 "30 January 2019" "PCRE2 10.33"
++.TH PCRE2POSIX 3 "26 April 2021" "PCRE2 10.37"
+ .SH NAME
+ PCRE2 - Perl-compatible regular expressions (revised API)
+ .SH "SYNOPSIS"
+@@ -44,11 +44,14 @@ can be accessed by adding \fB-lpcre2-posix\fP to the command for linking an
+ application. Because the POSIX functions call the native ones, it is also
+ necessary to add \fB-lpcre2-8\fP.
+ .P
+-Although they are not defined as protypes in \fBpcre2posix.h\fP, the library
+-does contain functions with the POSIX names \fBregcomp()\fP etc. These simply
+-pass their arguments to the PCRE2 functions. These functions are provided for
+-backwards compatibility with earlier versions of PCRE2, so that existing
+-programs do not have to be recompiled.
++Although they were not defined as protypes in \fBpcre2posix.h\fP, releases
++10.33 to 10.36 of the library contained functions with the POSIX names
++\fBregcomp()\fP etc. These simply passed their arguments to the PCRE2
++functions. These functions were provided for backwards compatibility with
++earlier versions of PCRE2, which had only POSIX names. However, this has proved
++troublesome in situations where a program links with several libraries, some of
++which use PCRE2's POSIX interface while others use the real POSIX functions.
++For this reason, the POSIX names have been removed since release 10.37.
+ .P
+ Calling the header file \fBpcre2posix.h\fP avoids any conflict with other POSIX
+ libraries. It can, of course, be renamed or aliased as \fBregex.h\fP, which is
+@@ -321,6 +324,6 @@ Cambridge, England.
+ .rs
+ .sp
+ .nf
+-Last updated: 30 January 2019
+-Copyright (c) 1997-2019 University of Cambridge.
++Last updated: 26 April 2021
++Copyright (c) 1997-2021 University of Cambridge.
+ .fi
diff --git a/src/pcre2posix.c b/src/pcre2posix.c
index b24620a4..32c80c3f 100644
--- a/src/pcre2posix.c
+++ b/src/pcre2posix.c
+@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+- New API code Copyright (c) 2016-2019 University of Cambridge
++ New API code Copyright (c) 2016-2021 University of Cambridge
+
+ -----------------------------------------------------------------------------
+ Redistribution and use in source and binary forms, with or without
@@ -175,6 +175,20 @@ static const char *const pstring[] = {
diff --git a/patches/pcre2-10.40-A-Fixed-a-unicode.patch b/patches/pcre2-10.40-A-Fixed-a-unicode.patch
index 2d89da9..ade86ba 100644
--- a/patches/pcre2-10.40-A-Fixed-a-unicode.patch
+++ b/patches/pcre2-10.40-A-Fixed-a-unicode.patch
@@ -4,11 +4,26 @@ Date: Thu Mar 24 05:34:42 2022 +0000
Fix incorrect value reading in JIT.
+diff --git a/src/pcre2_jit_compile.c b/src/pcre2_jit_compile.c
+index 94f6a588..7fcdac86 100644
+--- a/src/pcre2_jit_compile.c
++++ b/src/pcre2_jit_compile.c
+@@ -7489,7 +7489,7 @@ while (*cc != XCL_END)
+ {
+ SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
+ cc++;
+- if (*cc == PT_CLIST && *cc == XCL_PROP)
++ if (*cc == PT_CLIST && cc[-1] == XCL_PROP)
+ {
+ other_cases = PRIV(ucd_caseless_sets) + cc[1];
+ while (*other_cases != NOTACHAR)
+
commit 50a51cb7e67268e6ad417eb07c9de9bfea5cc55a
Author: Zoltan Herczeg
Date: Wed Mar 23 07:53:25 2022 +0000
Fixed a unicode properrty matching issue in JIT
+
diff --git a/ChangeLog b/ChangeLog
index f0eab7ba..ffb08805 100644
--- a/ChangeLog
@@ -24,7 +39,7 @@ index f0eab7ba..ffb08805 100644
Version 10.39 29-October-2021
-----------------------------
diff --git a/src/pcre2_jit_compile.c b/src/pcre2_jit_compile.c
-index e7dd26c5..7fcdac86 100644
+index e7dd26c5..94f6a588 100644
--- a/src/pcre2_jit_compile.c
+++ b/src/pcre2_jit_compile.c
@@ -7489,7 +7489,7 @@ while (*cc != XCL_END)
@@ -32,7 +47,7 @@ index e7dd26c5..7fcdac86 100644
SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
cc++;
- if (*cc == PT_CLIST)
-+ if (*cc == PT_CLIST && cc[-1] == XCL_PROP)
++ if (*cc == PT_CLIST && *cc == XCL_PROP)
{
other_cases = PRIV(ucd_caseless_sets) + cc[1];
while (*other_cases != NOTACHAR)
diff --git a/patches/pcre2-10.43-Avoid-LIMIT_HEAP-integer.patch b/patches/pcre2-10.43-Avoid-LIMIT_HEAP-integer.patch
index 9a9d020..9eb6b2f 100644
--- a/patches/pcre2-10.43-Avoid-LIMIT_HEAP-integer.patch
+++ b/patches/pcre2-10.43-Avoid-LIMIT_HEAP-integer.patch
@@ -1,38 +1,32 @@
-From bfb55a6bd406ae711444915bba957b933aaa10ca Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Carlo=20Marcelo=20Arenas=20Bel=C3=B3n?=
-Date: Tue, 17 Jan 2023 06:55:53 -0800
-Subject: [PATCH 1/2] avoid LIMIT_HEAP integer multiplication wrap around
- (#184)
+commit 4d66adc387baa2d29f91f0cadfaf8d8e77e13bb3
+Author: Carlo Marcelo Arenas Belón
+Date: Tue Jan 17 06:55:53 2023 -0800
-Cherry-picked from 4d66adc387baa2d29f91f0cadfaf8d8e77e13bb3.
-
-If a LIMIT_HEAP value once converted to bytes is larger than UINT_MAX
-would result in a bogus setting that could trigger a matching failure
-as shown by the following:
-
- PCRE2 version 10.42 2022-12-11
- re> /(*LIMIT_HEAP=4194304)a/
- data> a
- Failed: error -63: heap limit exceeded
-
-Remove the multiplication and instead keep track of the maximum heap
-allowed in KB as was done originally.
-
-Aditionally, add a check to avoid overflowing a PCRE2_SIZE while
-doubling the heap used and that could result in a crash (only on
-systems with a 32-bit PCRE2_SIZE and using non standard settings).
-
-Unlike the original, this code avoids rounding the heapframes_size
-to the frame_size at the allocation time, which simplifies the logic
-and wasn't really needed.
-
-Fixes: d90fb23 (Refactor match_data() to always use the heap instead
- of having an initial frames vector on the stack..., 2022-07-27)
-Closes: #183
----
- src/pcre2_intmodedep.h | 4 ++--
- src/pcre2_match.c | 38 +++++++++++++++++++++++++++-----------
- 2 files changed, 29 insertions(+), 13 deletions(-)
+ avoid LIMIT_HEAP integer multiplication wrap around (#184)
+
+ If a LIMIT_HEAP value once converted to bytes is larger than UINT_MAX
+ would result in a bogus setting that could trigger a matching failure
+ as shown by the following:
+
+ PCRE2 version 10.42 2022-12-11
+ re> /(*LIMIT_HEAP=4194304)a/
+ data> a
+ Failed: error -63: heap limit exceeded
+
+ Remove the multiplication and instead keep track of the maximum heap
+ allowed in KB as was done originally.
+
+ Aditionally, add a check to avoid overflowing a PCRE2_SIZE while
+ doubling the heap used and that could result in a crash (only on
+ systems with a 32-bit PCRE2_SIZE and using non standard settings).
+
+ Unlike the original, this code avoids rounding the heapframes_size
+ to the frame_size at the allocation time, which simplifies the logic
+ and wasn't really needed.
+
+ Fixes: d90fb23 (Refactor match_data() to always use the heap instead
+ of having an initial frames vector on the stack..., 2022-07-27)
+ Closes: #183
diff --git a/src/pcre2_intmodedep.h b/src/pcre2_intmodedep.h
index 390e737a..8f6487e9 100644
@@ -132,6 +126,3 @@ index 168b9fad..fa49e64a 100644
if (match_data->heapframes_size < heapframes_size)
{
---
-2.51.2.vfs.0.0
-
diff --git a/patches/pcre2-10.43-Fix-heapframe-overflow.patch b/patches/pcre2-10.43-Fix-heapframe-overflow.patch
index e5d5948..640ddb9 100644
--- a/patches/pcre2-10.43-Fix-heapframe-overflow.patch
+++ b/patches/pcre2-10.43-Fix-heapframe-overflow.patch
@@ -1,17 +1,27 @@
-From ba0a3ff395d99ab2fe7ee76f96c97736294298c6 Mon Sep 17 00:00:00 2001
-From: Philip Hazel
-Date: Fri, 18 Aug 2023 17:40:16 +0100
-Subject: [PATCH 2/2] Fix issue #275
+commit 803a64f6151a2d43a44a2377956ae36408c96986
+Author: Philip Hazel
+Date: Fri Aug 18 17:40:16 2023 +0100
-Cherry-picked from 803a64f6151a2d43a44a2377956ae36408c96986.
----
- src/pcre2_match.c | 32 +++++++++++++++-----------------
- testdata/testinput15 | 7 ++++++-
- testdata/testoutput15 | 8 +++++++-
- 3 files changed, 28 insertions(+), 19 deletions(-)
+ Fix issue #275
+diff --git a/ChangeLog b/ChangeLog
+index e2885418..3d594cd1 100644
+--- a/ChangeLog
++++ b/ChangeLog
+@@ -101,6 +101,11 @@ source-tree CMake build testing.
+
+ 26. Add support for LoongArch in JIT.
+
++27. Fixed a bug in pcre2_match() in the code for handling the vector of
++backtracking frames on the heap, which caused a heap overflow if *LIMIT_HEAP
++restricted an attempt to extend to less than the frame size. Generally tidy up
++the code for extending the heap frames vector. This fixes GitHub issue #275.
++
+
+ Version 10.42 11-December-2022
+ ------------------------------
diff --git a/src/pcre2_match.c b/src/pcre2_match.c
-index fa49e64a..8d3c796e 100644
+index f69ec0db..5ce17926 100644
--- a/src/pcre2_match.c
+++ b/src/pcre2_match.c
@@ -597,7 +597,6 @@ heapframe *P = NULL;
@@ -22,7 +32,7 @@ index fa49e64a..8d3c796e 100644
PCRE2_SIZE frame_copy_size; /* Amount to copy when creating a new frame */
/* Local variables that do not need to be preserved over calls to RRMATCH(). */
-@@ -635,13 +634,10 @@ copied when a new frame is created. */
+@@ -637,13 +636,10 @@ copied when a new frame is created. */
frame_copy_size = frame_size - offsetof(heapframe, eptr);
@@ -38,7 +48,7 @@ index fa49e64a..8d3c796e 100644
Frdepth = 0; /* "Recursion" depth */
Fcapture_last = 0; /* Number of most recent capture */
-@@ -662,10 +658,11 @@ MATCH_RECURSE:
+@@ -664,10 +660,11 @@ MATCH_RECURSE:
doubling the size, but constrained by the heap limit (which is in KiB). */
N = (heapframe *)((char *)F + frame_size);
@@ -51,7 +61,7 @@ index fa49e64a..8d3c796e 100644
if (match_data->heapframes_size >= PCRE2_SIZE_MAX / 2)
{
-@@ -679,7 +676,8 @@ if (N >= frames_top)
+@@ -681,7 +678,8 @@ if (N >= frames_top)
if (newsize / 1024 >= mb->heap_limit)
{
PCRE2_SIZE old_size = match_data->heapframes_size / 1024;
@@ -61,7 +71,7 @@ index fa49e64a..8d3c796e 100644
else
{
PCRE2_SIZE max_delta = 1024 * (mb->heap_limit - old_size);
-@@ -689,19 +687,21 @@ if (N >= frames_top)
+@@ -691,19 +689,21 @@ if (N >= frames_top)
}
}
@@ -89,7 +99,7 @@ index fa49e64a..8d3c796e 100644
}
#ifdef DEBUG_SHOW_RMATCH
-@@ -6842,8 +6842,7 @@ mb->match_limit_depth = (mcontext->depth_limit < re->limit_depth)?
+@@ -6935,8 +6935,7 @@ mb->match_limit_depth = (mcontext->depth_limit < re->limit_depth)?
/* If a pattern has very many capturing parentheses, the frame size may be very
large. Set the initial frame vector size to ensure that there are at least 10
available frames, but enforce a minimum of START_FRAMES_SIZE. If this is
@@ -99,7 +109,7 @@ index fa49e64a..8d3c796e 100644
heapframes_size = frame_size * 10;
if (heapframes_size < START_FRAMES_SIZE) heapframes_size = START_FRAMES_SIZE;
-@@ -7301,7 +7300,6 @@ for(;;)
+@@ -7394,7 +7393,6 @@ for(;;)
mb->match_call_count = 0;
mb->end_offset_top = 0;
mb->skip_arg_count = 0;
@@ -155,6 +165,3 @@ index af0d7c2a..be7afd0f 100644
/(a+)*zz/I
Capture group count = 1
Starting code units: a z
---
-2.51.2.vfs.0.0
-
diff --git a/patches/pcre2-10.44-Fix-incorrect-compiling.patch b/patches/pcre2-10.44-Fix-incorrect-compiling.patch
index 6b951f9..5b6ca94 100644
--- a/patches/pcre2-10.44-Fix-incorrect-compiling.patch
+++ b/patches/pcre2-10.44-Fix-incorrect-compiling.patch
@@ -1,22 +1,35 @@
-From 0d7159ca52771daa8b5cafc422b6c140aa7a11d7 Mon Sep 17 00:00:00 2001
-From: Philip Hazel
-Date: Fri, 1 Mar 2024 17:23:34 +0000
-Subject: [PATCH] Fix incorrect compiling when variable-length lookbehind's
- first branch was not the shortest and there was a backreference to a
- groupwithin the lookbehind.
+commit 4a6a8b056f39079d5e958eac84c2ad173f4680bc
+Author: Philip Hazel
+Date: Fri Mar 1 17:23:34 2024 +0000
-Cherry-picked from 4a6a8b056f39079d5e958eac84c2ad173f4680bc.
----
- src/pcre2_compile.c | 2 +-
- testdata/testinput2 | 4 ++++
- testdata/testoutput2 | 10 ++++++++++
- 3 files changed, 15 insertions(+), 1 deletion(-)
+ Fix incorrect compiling when variable-length lookbehind's first branch was not the shortest and there was a backreference to a groupwithin the lookbehind.
+diff --git a/ChangeLog b/ChangeLog
+index 0568108a..6b78659e 100644
+--- a/ChangeLog
++++ b/ChangeLog
+@@ -4,6 +4,16 @@ Change Log for PCRE2
+ Before the move to GitHub, this was the only record of changes to PCRE2. Now
+ there is often more detail in the pull requests.
+
++Version 10.44 xx-xxx-2024
++-------------------------
++
++1. If a pattern contained a variable-length lookbehind in which the first
++branch was not the one with the shortest minimym length, and the lookbehind
++contained a capturing group, and elsewhere in the pattern there was another
++lookbehind that referenced that group, the pattern was incorrectly compiled,
++leading to unpredictable results, including crashes in JIT compiling. An
++example pattern is: /(((?<=123?456456|ABC)))(?<=\2)/
++
+
+ Version 10.43 16-February-2024
+ ------------------------------
diff --git a/src/pcre2_compile.c b/src/pcre2_compile.c
-index 8b364977..71c2dbca 100644
+index 95c97710..e66e40f6 100644
--- a/src/pcre2_compile.c
+++ b/src/pcre2_compile.c
-@@ -9908,7 +9908,7 @@ do
+@@ -9909,7 +9909,7 @@ do
*bptr |= branchlength; /* branchlength never more than 65535 */
bptr = *pptrptr;
}
@@ -59,6 +72,3 @@ index ee1f70b0..30c5a83e 100644
# End of testinput2
Error -70: PCRE2_ERROR_BADDATA (unknown error number)
Error -62: bad serialized data
---
-2.51.2.vfs.0.0
-
diff --git a/patches/pcre2-10.44-Fix-locking-region.patch b/patches/pcre2-10.44-Fix-locking-region.patch
index 39c1fb0..5e159ce 100644
--- a/patches/pcre2-10.44-Fix-locking-region.patch
+++ b/patches/pcre2-10.44-Fix-locking-region.patch
@@ -1,19 +1,17 @@
-From c0fdb5f7013ecc10292ed9e697b3fe901e38cd77 Mon Sep 17 00:00:00 2001
-From: lbonn
-Date: Tue, 2 Apr 2024 12:55:33 +0200
-Subject: [PATCH] Fix locking region in sjlit_malloc_exec
+commit c0fdb5f7013ecc10292ed9e697b3fe901e38cd77
+Author: lbonn
+Date: Tue Apr 2 12:55:33 2024 +0200
-Cherry-picked from ad89dd8ecd25589d236bd20b36f2abf69f938fd1
-(https://github.com/zherczeg/sljit.git)
-
-The locked section needs to extend until we are done modifying internal
-block offsets and sizes, otherwise we risk running into data corruption
-in a multi-threaded context.
-
-This bug was introduced in 7de0fee9a7376b33e31a3903487cd9933da3a606
----
- src/sljit/allocator_src/sljitExecAllocatorCore.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
+ Fix locking region in sjlit_malloc_exec
+
+ Cherry-picked from ad89dd8ecd25589d236bd20b36f2abf69f938fd1
+ (https://github.com/zherczeg/sljit.git)
+
+ The locked section needs to extend until we are done modifying internal
+ block offsets and sizes, otherwise we risk running into data corruption
+ in a multi-threaded context.
+
+ This bug was introduced in 7de0fee9a7376b33e31a3903487cd9933da3a606
diff --git a/src/sljit/allocator_src/sljitExecAllocatorCore.c b/src/sljit/allocator_src/sljitExecAllocatorCore.c
index 6cd39110..4ef39c17 100644
@@ -33,6 +31,3 @@ index 6cd39110..4ef39c17 100644
return MEM_START(header);
}
---
-2.51.2.vfs.0.0
-
diff --git a/patches/pcre2-10.45-Memory-reports-only-compiled.patch b/patches/pcre2-10.45-Memory-reports-only-compiled.patch
index 9338088..b6b9fc7 100644
--- a/patches/pcre2-10.45-Memory-reports-only-compiled.patch
+++ b/patches/pcre2-10.45-Memory-reports-only-compiled.patch
@@ -1,39 +1,23 @@
-From e669b61ecf6ae3af2a4f0c714c6723ccc073ecd5 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Carlo=20Marcelo=20Arenas=20Bel=C3=B3n?=
-Date: Sun, 9 Jun 2024 08:22:15 -0700
-Subject: [PATCH] pcre2test: memory reports only compiled memory usage for
- code/data (#418)
+commit 57906628d7babd27c01eb1c085d3e0cdd512189a
+Author: Carlo Marcelo Arenas Belón
+Date: Sun Jun 9 08:22:15 2024 -0700
-Cherry-pick of 57906628d7babd27c01eb1c085d3e0cdd512189a.
-
-Since 05aafb2 (Implement pcre2_set_max_pattern_compiled_length() and set
-this limit in the fuzzer, 2024-04-24), the memory modifier has reported
-the full size of the allocated "code" returned by `pcre2_compile`.
-
-Problem is that the size of the structure used to hold that in memory also
-depends on the platform ABI and even alignment by the compiler, and has
-been therefore fragile to compare.
-
-Revert to reporting only the additional memory that `pcre2_compile()` will
-use for the compiled pattern (including any data tables) and make sure
-that the limit provided with `pcre2_set_max_pattern_compiled_length()`
-also avoid the internal struct overhead.
-
-Fixes: #415
----
- doc/pcre2_set_max_pattern_compiled_length.3 | 8 +-
- src/pcre2_compile.c | 4 +-
- src/pcre2test.c | 17 +-
- testdata/testoutput8-16-2 | 171 +++++++-------------
- testdata/testoutput8-16-3 | 171 +++++++-------------
- testdata/testoutput8-16-4 | 171 +++++++-------------
- testdata/testoutput8-32-2 | 171 +++++++-------------
- testdata/testoutput8-32-3 | 171 +++++++-------------
- testdata/testoutput8-32-4 | 171 +++++++-------------
- testdata/testoutput8-8-2 | 171 +++++++-------------
- testdata/testoutput8-8-3 | 171 +++++++-------------
- testdata/testoutput8-8-4 | 171 +++++++-------------
- 12 files changed, 546 insertions(+), 1022 deletions(-)
+ pcre2test: memory reports only compiled memory usage for code/data (#418)
+
+ Since 05aafb2 (Implement pcre2_set_max_pattern_compiled_length() and set
+ this limit in the fuzzer, 2024-04-24), the memory modifier has reported
+ the full size of the allocated "code" returned by `pcre2_compile`.
+
+ Problem is that the size of the structure used to hold that in memory also
+ depends on the platform ABI and even alignment by the compiler, and has
+ been therefore fragile to compare.
+
+ Revert to reporting only the additional memory that `pcre2_compile()` will
+ use for the compiled pattern (including any data tables) and make sure
+ that the limit provided with `pcre2_set_max_pattern_compiled_length()`
+ also avoid the internal struct overhead.
+
+ Fixes: #415
diff --git a/doc/pcre2_set_max_pattern_compiled_length.3 b/doc/pcre2_set_max_pattern_compiled_length.3
index 472a7bbd..679c12c2 100644
@@ -5223,6 +5207,3 @@ index 81cf0f76..8bfac41a 100644
------------------------------------------------------------------
0 8 Bra
5 [^\x{aa}]
---
-2.51.2.vfs.0.0
-
diff --git a/patches/pcre2-10.47-Fix-for-callback.patch b/patches/pcre2-10.47-Fix-for-callback.patch
index 7ec98fe..c1e81ae 100644
--- a/patches/pcre2-10.47-Fix-for-callback.patch
+++ b/patches/pcre2-10.47-Fix-for-callback.patch
@@ -1,36 +1,28 @@
-From 39c3fd67ef9ca22c39f128bf476e238b0e886975 Mon Sep 17 00:00:00 2001
-From: Nicholas Wilson
-Date: Fri, 26 Sep 2025 11:37:10 +0100
-Subject: [PATCH] Add fix and tests for callback enumerate (#801)
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
+commit cc6c84d0207d9d09ca9e42996f0bc50353c03157
+Author: Nicholas Wilson
+Date: Fri Sep 26 11:37:10 2025 +0100
-Cherry-pick of commit cc6c84d0207d9d09ca9e42996f0bc50353c03157.
-
-This is a bug in PCRE2 10.45 and 10.46, not present in 10.44 and earlier.
-
-The bug is that applications using pcre2_callout_enumerate() will crash badly on patterns with Unicode (ie non-ASCII) character classes. There is an out-of-bounds read of arbitrary length, including misinterpreting the bytes as offsets, allowing the read to jump forwards in memory to pretty much anywhere.
-
-Applications which call pcre2_callout_enumerate should potentially downgrade to PCRE2 10.44 until we release an update of PCRE2 with the fix.
-
-Since this function is (clearly!!) not used often by applications, I am not currently treating this as very high severity. There is no way for an attacker to make any application call this function, if it is not currently using it.
-
-The root cause seems to be commit 24f9d8d (#540).
-
----------
-
-Co-authored-by: Carlo Marcelo Arenas Belón
----
- src/pcre2_pattern_info.c | 3 +-
- src/pcre2test.c | 61 ++++++++++++++++++++++------------------
- 2 files changed, 34 insertions(+), 30 deletions(-)
+ Add fix and tests for callback enumerate (#801)
+
+ This is a bug in PCRE2 10.45 and 10.46, not present in 10.44 and earlier.
+
+ The bug is that applications using pcre2_callout_enumerate() will crash badly on patterns with Unicode (ie non-ASCII) character classes. There is an out-of-bounds read of arbitrary length, including misinterpreting the bytes as offsets, allowing the read to jump forwards in memory to pretty much anywhere.
+
+ Applications which call pcre2_callout_enumerate should potentially downgrade to PCRE2 10.44 until we release an update of PCRE2 with the fix.
+
+ Since this function is (clearly!!) not used often by applications, I am not currently treating this as very high severity. There is no way for an attacker to make any application call this function, if it is not currently using it.
+
+ The root cause seems to be commit 24f9d8d (#540).
+
+ ---------
+
+ Co-authored-by: Carlo Marcelo Arenas Belón
diff --git a/src/pcre2_pattern_info.c b/src/pcre2_pattern_info.c
-index fe4d3c66..c49eaf69 100644
+index d8786318..e0bd83a9 100644
--- a/src/pcre2_pattern_info.c
+++ b/src/pcre2_pattern_info.c
-@@ -292,8 +292,7 @@ if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+@@ -289,8 +289,7 @@ if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
if ((re->flags & (PCRE2_CODE_UNIT_WIDTH/8)) == 0) return PCRE2_ERROR_BADMODE;
cb.version = 0;
@@ -41,10 +33,10 @@ index fe4d3c66..c49eaf69 100644
while (TRUE)
{
diff --git a/src/pcre2test.c b/src/pcre2test.c
-index 80ab4f80..6ac638ce 100644
+index b2620f59..dbb1cb56 100644
--- a/src/pcre2test.c
+++ b/src/pcre2test.c
-@@ -512,7 +512,6 @@ so many of them that they are split into two fields. */
+@@ -558,7 +558,6 @@ so many of them that they are split into two fields. */
/* Combinations */
#define CTL_DEBUG (CTL_FULLBINCODE|CTL_INFO) /* For setting */
@@ -52,30 +44,17 @@ index 80ab4f80..6ac638ce 100644
#define CTL_ANYGLOB (CTL_ALTGLOBAL|CTL_GLOBAL)
/* Second control word */
-@@ -4652,6 +4651,16 @@ fprintf(outfile, "%.*s\n",
- return 0;
- }
-
-+/* Backport from 10.47 */
-+
-+static int callout_enumerate_function_void(pcre2_callout_enumerate_block_8 *cb,
-+ void *callout_data)
-+{
-+(void)cb;
-+(void)callout_data;
-+return 0;
-+}
-+
-
-
- /*************************************************
-@@ -4671,9 +4680,16 @@ Returns: PR_OK continue processing next line
+diff --git a/src/pcre2test_inc.h b/src/pcre2test_inc.h
+index 28673ebb..5b5f6424 100644
+--- a/src/pcre2test_inc.h
++++ b/src/pcre2test_inc.h
+@@ -1258,9 +1258,16 @@ Returns: PR_OK continue processing next line
static int
show_pattern_info(void)
{
+int rc;
uint32_t compile_options, overall_options, extra_options;
- BOOL utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0;
+ BOOL utf = (compiled_code->overall_options & PCRE2_UTF) != 0;
+if ((pat_patctl.control & CTL_MEMORY) != 0)
+ show_memory_info();
@@ -86,20 +65,20 @@ index 80ab4f80..6ac638ce 100644
if ((pat_patctl.control & (CTL_BINCODE|CTL_FULLBINCODE)) != 0)
{
fprintf(outfile, "------------------------------------------------------------------\n");
-@@ -5016,17 +5032,17 @@ if ((pat_patctl.control & CTL_INFO) != 0)
+@@ -1586,17 +1593,17 @@ if ((pat_patctl.control & CTL_INFO) != 0)
}
}
-if ((pat_patctl.control & CTL_CALLOUT_INFO) != 0)
-+PCRE2_CALLOUT_ENUMERATE(rc,
-+ (((pat_patctl.control & CTL_CALLOUT_INFO) != 0)? callout_callback :
++rc = pcre2_callout_enumerate(compiled_code,
++ ((pat_patctl.control & CTL_CALLOUT_INFO) != 0)? callout_enumerate_function :
+ /* Exercise the callout enumeration code with a dummy callback to make sure
+ it works. */
-+ callout_enumerate_function_void), 0);
++ callout_enumerate_function_void, NULL);
+if (rc != 0)
{
-- int errorcode;
-- PCRE2_CALLOUT_ENUMERATE(errorcode, callout_callback, 0);
+- int errorcode = pcre2_callout_enumerate(compiled_code,
+- callout_enumerate_function, NULL);
- if (errorcode != 0)
- {
- fprintf(outfile, "Callout enumerate failed: error %d: ", errorcode);
@@ -114,9 +93,9 @@ index 80ab4f80..6ac638ce 100644
}
return PR_OK;
-@@ -5230,13 +5246,9 @@ switch(cmd)
+@@ -1763,13 +1770,9 @@ switch(cmd)
{
- PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit);
+ jitrc = pcre2_jit_compile(compiled_code, pat_patctl.jit);
}
- if ((pat_patctl.control & CTL_MEMORY) != 0) show_memory_info();
- if ((pat_patctl.control2 & CTL2_FRAMESIZE) != 0) show_framesize();
@@ -131,32 +110,32 @@ index 80ab4f80..6ac638ce 100644
break;
/* Save the stack of compiled patterns to a file, then empty the stack. */
-@@ -5395,7 +5407,7 @@ BOOL utf;
+@@ -1979,7 +1982,7 @@ BOOL utf;
uint32_t k;
uint8_t *p = buffer;
unsigned int delimiter = *p++;
-int errorcode;
+int rc, errorcode;
- void *use_pat_context;
- void *use_pbuffer = NULL;
+ pcre2_compile_context *use_pat_context;
+ PCRE2_SPTR use_pbuffer = NULL;
uint32_t use_forbid_utf = forbid_utf;
-@@ -5724,7 +5736,6 @@ local character tables. Neither does it have 16-bit or 32-bit support. */
- if ((pat_patctl.control & CTL_POSIX) != 0)
- {
- #ifdef SUPPORT_PCRE2_8
+@@ -2313,7 +2316,6 @@ if ((pat_patctl.control & CTL_POSIX) != 0)
+ return PR_SKIP;
+
+ #else
- int rc;
int cflags = 0;
const char *msg = "** Ignored with POSIX interface:";
- #endif
-@@ -5931,7 +5942,6 @@ ends up back in the usual place. */
+
+@@ -2523,7 +2525,6 @@ ends up back in the usual place. */
if (pat_patctl.convert_type != CONVERT_UNSET)
{
- int rc;
int convert_return = PR_OK;
uint32_t convert_options = pat_patctl.convert_type;
- void *converted_pattern;
-@@ -6246,13 +6256,8 @@ if ((pat_patctl.control2 & CTL2_NL_SET) != 0)
+ PCRE2_UCHAR *converted_pattern;
+@@ -2918,13 +2919,8 @@ if ((pat_patctl.control2 & CTL2_NL_SET) != 0)
/* Output code size and other information if requested. */
@@ -172,6 +151,3 @@ index 80ab4f80..6ac638ce 100644
/* The "push" control requests that the compiled pattern be remembered on a
stack. This is mainly for testing the serialization functionality. */
---
-2.51.2.vfs.0.0
-
diff --git a/patches/pcre2-10.48-Check-JIT-mode-before-validation.patch b/patches/pcre2-10.48-Check-JIT-mode-before-validation.patch
new file mode 100644
index 0000000..7bf7eb2
--- /dev/null
+++ b/patches/pcre2-10.48-Check-JIT-mode-before-validation.patch
@@ -0,0 +1,382 @@
+commit f67db227af31bba7cdf2a7a00b97af91b588c2f5
+Author: Zoltan Herczeg
+Date: Sun Aug 9 11:05:54 2026 +0200
+
+ Fix pcre2_match to check for JIT support before JIT validation & execution (#926)
+
+ This fixes the issue that the JIT branch's UTF validation is not pinned to be identical to the interpreter's validation.
+
+ This was not robust, and lead to a bug, in the case where the JIT UTF validation is done, but because the relevant JIT mode was not compiled, it falls through to the interpreter and skips the interpreter's own UTF validation and setup.
+
+diff --git a/src/pcre2_internal.h b/src/pcre2_internal.h
+index 2e8c7e47..930c745b 100644
+--- a/src/pcre2_internal.h
++++ b/src/pcre2_internal.h
+@@ -2301,6 +2301,7 @@ is available. */
+ #define _pcre2_is_newline PCRE2_SUFFIX(_pcre2_is_newline_)
+ #define _pcre2_jit_free_rodata PCRE2_SUFFIX(_pcre2_jit_free_rodata_)
+ #define _pcre2_jit_free PCRE2_SUFFIX(_pcre2_jit_free_)
++#define _pcre2_jit_check_exec PCRE2_SUFFIX(_pcre2_jit_check_exec_)
+ #define _pcre2_jit_get_size PCRE2_SUFFIX(_pcre2_jit_get_size_)
+ #define _pcre2_jit_get_target PCRE2_SUFFIX(_pcre2_jit_get_target_)
+ #define _pcre2_memctl_malloc PCRE2_SUFFIX(_pcre2_memctl_malloc_)
+@@ -2330,6 +2331,7 @@ extern BOOL _pcre2_is_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR,
+ uint32_t *, BOOL);
+ extern void _pcre2_jit_free_rodata(void *, void *);
+ extern void _pcre2_jit_free(void *, pcre2_memctl *);
++extern BOOL _pcre2_jit_check_exec(void *, uint32_t);
+ extern size_t _pcre2_jit_get_size(void *);
+ const char * _pcre2_jit_get_target(void);
+ extern void * _pcre2_memctl_malloc(size_t, pcre2_memctl *);
+diff --git a/src/pcre2_jit_match_inc.h b/src/pcre2_jit_match_inc.h
+index 4163cf61..ba210007 100644
+--- a/src/pcre2_jit_match_inc.h
++++ b/src/pcre2_jit_match_inc.h
+@@ -117,6 +117,7 @@ jit_arguments arguments;
+ int rc;
+ int index = 0;
+
++/* The same check is performed by jit_check_exec(). */
+ if ((options & PCRE2_PARTIAL_HARD) != 0)
+ index = 2;
+ else if ((options & PCRE2_PARTIAL_SOFT) != 0)
+diff --git a/src/pcre2_jit_misc_inc.h b/src/pcre2_jit_misc_inc.h
+index 0225fc6b..16c230e9 100644
+--- a/src/pcre2_jit_misc_inc.h
++++ b/src/pcre2_jit_misc_inc.h
+@@ -200,17 +200,28 @@ if (jit_stack != NULL)
+
+
+ /*************************************************
+-* Get target CPU type *
++* Checks function compilation *
+ *************************************************/
+
+-const char*
+-PRIV(jit_get_target)(void)
++BOOL
++PRIV(jit_check_exec)(void *executable_jit, uint32_t options)
+ {
+ #ifndef SUPPORT_JIT
+-return "JIT is not supported";
++(void)executable_jit;
++(void)options;
++return FALSE;
+ #else /* SUPPORT_JIT */
+-return sljit_get_platform_name();
+-#endif /* SUPPORT_JIT */
++/* The same check is performed at the beginning of pcre2_jit_match(). */
++executable_functions *functions = (executable_functions *)executable_jit;
++int index = 0;
++
++if ((options & PCRE2_PARTIAL_HARD) != 0)
++ index = 2;
++else if ((options & PCRE2_PARTIAL_SOFT) != 0)
++ index = 1;
++
++return functions->executable_funcs[index] != NULL;
++#endif
+ }
+
+
+@@ -231,4 +242,19 @@ return executable_sizes[0] + executable_sizes[1] + executable_sizes[2];
+ #endif
+ }
+
++/*************************************************
++* Get target CPU type *
++*************************************************/
++
++const char*
++PRIV(jit_get_target)(void)
++{
++#ifndef SUPPORT_JIT
++return "JIT is not supported";
++#else /* SUPPORT_JIT */
++return sljit_get_platform_name();
++#endif /* SUPPORT_JIT */
++}
++
++
+ /* End of pcre2_jit_misc_inc.h */
+diff --git a/src/pcre2_match.c b/src/pcre2_match.c
+index 9ee8a476..a5a8421f 100644
+--- a/src/pcre2_match.c
++++ b/src/pcre2_match.c
+@@ -7005,10 +7005,6 @@ PCRE2_SPTR req_cu_ptr;
+ PCRE2_SPTR start_partial;
+ PCRE2_SPTR match_partial;
+
+-#ifdef SUPPORT_JIT
+-BOOL use_jit;
+-#endif
+-
+ /* This flag is needed even when Unicode is not supported for convenience
+ (it is used by the IS_NEWLINE macro). */
+
+@@ -7018,9 +7014,6 @@ BOOL utf = FALSE;
+ BOOL ucp = FALSE;
+ BOOL allow_invalid;
+ uint32_t fragment_options = 0;
+-#ifdef SUPPORT_JIT
+-BOOL jit_checked_utf = FALSE;
+-#endif
+ #endif /* SUPPORT_UNICODE */
+
+ PCRE2_SIZE frame_size;
+@@ -7083,15 +7076,6 @@ options |= (re->flags & FF) / ((FF & (~FF+1)) / (OO & (~OO+1)));
+ #undef FF
+ #undef OO
+
+-/* If the pattern was successfully studied with JIT support, we will run the
+-JIT executable instead of the rest of this function. Most options must be set
+-at compile time for the JIT code to be usable. */
+-
+-#ifdef SUPPORT_JIT
+-use_jit = (re->executable_jit != NULL &&
+- (options & ~PUBLIC_JIT_MATCH_OPTIONS) == 0);
+-#endif
+-
+ /* Initialize UTF/UCP parameters. */
+
+ #ifdef SUPPORT_UNICODE
+@@ -7138,20 +7122,25 @@ match_data->startchar = 0;
+
+ /* ============================= JIT matching ============================== */
+
+-/* Prepare for JIT matching. Check a UTF string for validity unless no check is
+-requested or invalid UTF can be handled. We check only the portion of the
+-subject that might be be inspected during matching - from the offset minus the
+-maximum lookbehind to the given length. This saves time when a small part of a
+-large subject is being matched by the use of a starting offset. Note that the
+-maximum lookbehind is a number of characters, not code units. */
++/* If the pattern was successfully studied with JIT support, we will run the
++JIT executable instead of the rest of this function. Most options must be set
++at compile time for the JIT code to be usable. */
+
+ #ifdef SUPPORT_JIT
+-if (use_jit)
++if (re->executable_jit != NULL &&
++ (options & ~PUBLIC_JIT_MATCH_OPTIONS) == 0 &&
++ PRIV(jit_check_exec)(re->executable_jit, options))
+ {
++ /* Prepare for JIT matching. Check a UTF string for validity unless no check
++ is requested or invalid UTF can be handled. We check only the portion of the
++ subject that might be be inspected during matching - from the offset minus
++ the maximum lookbehind to the given length. This saves time when a small part
++ of a large subject is being matched by the use of a starting offset. Note that
++ the maximum lookbehind is a number of characters, not code units. */
++
+ #ifdef SUPPORT_UNICODE
+ if (utf && (options & PCRE2_NO_UTF_CHECK) == 0 && !allow_invalid)
+ {
+-
+ /* For 8-bit and 16-bit UTF, check that the first code unit is a valid
+ character start. */
+
+@@ -7204,40 +7193,36 @@ if (use_jit)
+ match_data->startchar += start_match - subject;
+ return match_data->rc = rc;
+ }
+- jit_checked_utf = TRUE;
+ }
+ #endif /* SUPPORT_UNICODE */
+
+- /* If JIT returns BADOPTION, which means that the selected complete or
+- partial matching mode was not compiled, fall through to the interpreter. */
+-
+ rc = pcre2_jit_match(code, subject, length, start_offset, options,
+ match_data, mcontext);
+- if (rc != PCRE2_ERROR_JIT_BADOPTION)
++ /* JIT must be able to perform the match. */
++ PCRE2_ASSERT(rc != PCRE2_ERROR_JIT_BADOPTION);
++
++ match_data->options = original_options;
++ if (rc >= 0 && (options & PCRE2_COPY_MATCHED_SUBJECT) != 0)
+ {
+- match_data->options = original_options;
+- if (rc >= 0 && (options & PCRE2_COPY_MATCHED_SUBJECT) != 0)
++ if (length != 0)
+ {
+- if (length != 0)
+- {
+- match_data->subject = match_data->memctl.malloc(CU2BYTES(length),
+- match_data->memctl.memory_data);
+- if (match_data->subject == NULL)
+- return match_data->rc = PCRE2_ERROR_NOMEMORY;
+- memcpy((void *)match_data->subject, subject, CU2BYTES(length));
+- }
+- else
+- match_data->subject = NULL;
+- match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
++ match_data->subject = match_data->memctl.malloc(CU2BYTES(length),
++ match_data->memctl.memory_data);
++ if (match_data->subject == NULL)
++ return match_data->rc = PCRE2_ERROR_NOMEMORY;
++ memcpy((void *)match_data->subject, subject, CU2BYTES(length));
+ }
+ else
+- {
+- /* When pcre2_jit_match sets the subject, it doesn't know what the
+- original passed-in pointer was. */
+- if (match_data->subject != NULL) match_data->subject = original_subject;
+- }
+- return rc;
++ match_data->subject = NULL;
++ match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
+ }
++ else
++ {
++ /* When pcre2_jit_match sets the subject, it doesn't know what the
++ original passed-in pointer was. */
++ if (match_data->subject != NULL) match_data->subject = original_subject;
++ }
++ return rc;
+ }
+ #endif /* SUPPORT_JIT */
+
+@@ -7250,12 +7235,8 @@ this. */
+
+ mb->check_subject = subject;
+
+-/* If a UTF subject string was not checked for validity in the JIT code above,
+-check it here, and handle support for invalid UTF strings. The check above
+-happens only when invalid UTF is not supported and PCRE2_NO_CHECK_UTF is unset.
+-If we get here in those circumstances, it means the subject string is valid,
+-but for some reason JIT matching was not successful. There is no need to check
+-the subject again.
++/* Check the validity of UTF subject strings. The check happens only when
++PCRE2_NO_CHECK_UTF is unset.
+
+ We check only the portion of the subject that might be be inspected during
+ matching - from the offset minus the maximum lookbehind to the given length.
+@@ -7267,11 +7248,7 @@ Note also that support for invalid UTF forces a check, overriding the setting
+ of PCRE2_NO_CHECK_UTF. */
+
+ #ifdef SUPPORT_UNICODE
+-if (utf &&
+-#ifdef SUPPORT_JIT
+- !jit_checked_utf &&
+-#endif
+- ((options & PCRE2_NO_UTF_CHECK) == 0 || allow_invalid))
++if (utf && ((options & PCRE2_NO_UTF_CHECK) == 0 || allow_invalid))
+ {
+ #if PCRE2_CODE_UNIT_WIDTH != 32
+ BOOL skipped_bad_start = FALSE;
+
+commit e2f100156b94cf85dce9046b47a3274590487de4
+Author: Nicholas Wilson
+Date: Wed Aug 12 10:18:54 2026 +0100
+
+ Add a testcase for #926 (#940)
+
+diff --git a/RunTest b/RunTest
+index 57a03455..306427b6 100755
+--- a/RunTest
++++ b/RunTest
+@@ -175,9 +175,12 @@ checkresult()
+ *) with="";;
+ esac
+ cf_out="$testdata/testoutput$2"
+- if [ $ebcdic -eq 1 ] ; then
+- # We currently only use the #if ... #endif support in pcre2test for EBCDIC
+- # testing. Run in "preprocess-only" mode (-E) on the testoutput file to trim
++ if [ $ebcdic -eq 1 ] || [ $utf -eq 0 ]; then
++ # We currently only use the #if ... #endif support in pcre2test for tests
++ # which are excluded in certain builds:
++ # - EBCDIC
++ # - No-UTF
++ # Run in "preprocess-only" mode (-E) on the testoutput file to trim
+ # the output lines matching the input lines which are discarded.
+ $sim $pcre2test -q -E "$cf_out" >testoutput$bits$3/testoutput$2-expected
+ cf_out=testoutput$bits$3/testoutput$2-expected
+diff --git a/src/pcre2test_inc.h b/src/pcre2test_inc.h
+index a74e3368..72767916 100644
+--- a/src/pcre2test_inc.h
++++ b/src/pcre2test_inc.h
+@@ -1712,7 +1712,7 @@ process_command(void)
+ FILE *f;
+ PCRE2_SIZE serial_size;
+ size_t i;
+-int rc, cmd, yield;
++int rc, cmd, yield, config_value;
+ uint16_t first_listed_newline;
+ const char *cmdname;
+ size_t cmdlen;
+@@ -1980,7 +1980,7 @@ switch(cmd)
+ {
+ size_t optlen = strlen(coptlist[i].name);
+ const uint8_t *argptr_trail;
+- if (coptlist[i].type != CONF_FIX)
++ if (coptlist[i].type != CONF_FIX && coptlist[i].type != CONF_INT)
+ continue;
+ if (strncmp((const char*)argptr, coptlist[i].name, optlen) != 0)
+ continue;
+@@ -1995,9 +1995,20 @@ switch(cmd)
+ return PR_ABEND;
+ }
+
+- /* Condition FALSE - skip this line and everything until #endif. */
+- if ((coptlist[i].value != 0) == if_inverted)
++ if (coptlist[i].type == CONF_FIX)
++ {
++ config_value = coptlist[i].value;
++ }
++ else /* if (coptlist[i].type == CONF_INT) */
++ {
++ (void)pcre2_config(coptlist[i].value, &config_value);
++ }
++
++ if ((config_value != 0) == if_inverted)
++ {
++ /* Condition FALSE - skip this line and everything until #endif. */
+ yield = PR_ENDIF;
++ }
+
+ inside_if = TRUE;
+ break;
+diff --git a/testdata/testinput17 b/testdata/testinput17
+index 9d728965..e6dbbe42 100644
+--- a/testdata/testinput17
++++ b/testdata/testinput17
+@@ -336,4 +336,14 @@
+ zabcz\=callout_error=1
+ zabcz\=callout_error=1,substitute_matched
+
++# Check UTF validation when falling back from a partially-compiled JIT pattern
++# to the interpreter
++
++#if unicode
++
++/\b/B,utf,ucp,jit=1
++ \xff\x00\x00\=offset=2,ps
++
++#endif
++
+ # End of testinput17
+diff --git a/testdata/testoutput17 b/testdata/testoutput17
+index 773ec18a..11f032d8 100644
+--- a/testdata/testoutput17
++++ b/testdata/testoutput17
+@@ -603,4 +603,21 @@ Failed: error -37: callout error code
+ 1 ^ a
+ Failed: error -37: callout error code
+
++# Check UTF validation when falling back from a partially-compiled JIT pattern
++# to the interpreter
++
++#if unicode
++
++/\b/B,utf,ucp,jit=1
++------------------------------------------------------------------
++ Bra
++ \b (ucp)
++ Ket
++ End
++------------------------------------------------------------------
++ \xff\x00\x00\=offset=2,ps
++Partial match:
++
++#endif
++
+ # End of testinput17
diff --git a/patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch b/patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch
new file mode 100644
index 0000000..81fb1b5
--- /dev/null
+++ b/patches/pcre2-10.48-Fix-DFA-workspace-overflows.patch
@@ -0,0 +1,149 @@
+commit c932e70451eafef922ebef364ac25042f0031135
+Author: Nicholas Wilson
+Date: Thu Aug 27 16:52:16 2026 +0100
+
+ Fix DFA workspace overflows; see GHSA-3r4p-g7gg-ppmf for details
+
+diff --git a/src/pcre2_dfa_match.c b/src/pcre2_dfa_match.c
+index 314e9775..8e9512c4 100644
+--- a/src/pcre2_dfa_match.c
++++ b/src/pcre2_dfa_match.c
+@@ -405,8 +405,8 @@ return (mb->callout)(cb, mb->callout_data);
+
+ /* This function is called when internal_dfa_match() is about to be called
+ recursively and there is insufficient working space left in the current
+-workspace block. If there's an existing next block, use it; otherwise get a new
+-block unless the heap limit is reached.
++workspace block. If there's a sufficiently large next block, use it; get a new
++block unless the heap limit is (or has been) reached.
+
+ Arguments:
+ rwsptr pointer to block pointer (updated)
+@@ -422,9 +422,18 @@ more_workspace(RWS_anchor **rwsptr, unsigned int ovecsize, dfa_match_block *mb)
+ {
+ RWS_anchor *rws = *rwsptr;
+ RWS_anchor *new;
++uint32_t requested;
++
++PCRE2_ASSERT(ovecsize <= UINT32_MAX - RWS_RSIZE - RWS_ANCHOR_SIZE);
++requested = RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE;
+
+ if (rws->next != NULL)
+ {
++ /* Although the initial block is large, and subsequent ones try to double, the
++ heap limit may cause the last one to be smaller; in this case, we have already
++ hit the heap limit and allocating a larger block will not be possible. */
++ if (rws->next->size < requested)
++ return PCRE2_ERROR_HEAPLIMIT;
+ new = rws->next;
+ }
+
+@@ -434,14 +443,30 @@ overflow. */
+
+ else
+ {
+- uint32_t newsize = (rws->size >= UINT32_MAX/(sizeof(int)*2))? UINT32_MAX/sizeof(int) : rws->size * 2;
++ uint32_t newsize = (rws->size >= (UINT32_MAX/sizeof(int))/2)?
++ UINT32_MAX/sizeof(int) : rws->size * 2;
+ uint32_t newsizeK = newsize/(1024/sizeof(int));
+
+- if (newsizeK + mb->heap_used > mb->heap_limit)
+- newsizeK = (uint32_t)(mb->heap_limit - mb->heap_used);
+- newsize = newsizeK*(1024/sizeof(int));
++ /* Clamp the allocation to the remaining heap allowance with care for overflows */
++
++ if (mb->heap_used >= mb->heap_limit)
++ {
++ newsize = 0;
++ newsizeK = 0;
++ }
++ else
++ {
++ PCRE2_SIZE availableK = mb->heap_limit - mb->heap_used;
++ /* newsize always capped at UINT32_MAX/sizeof(int), so newsizeK also capped;
++ and - if availableK is smaller - then multiplication to form newsize is safe */
++ if (newsizeK > availableK)
++ {
++ newsize = (uint32_t)(availableK*(1024/sizeof(int)));
++ newsizeK = availableK;
++ }
++ }
+
+- if (newsize < RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE)
++ if (newsize < requested)
+ return PCRE2_ERROR_HEAPLIMIT;
+ new = mb->memctl.malloc(newsize*sizeof(int), mb->memctl.memory_data);
+ if (new == NULL) return PCRE2_ERROR_NOMEMORY;
+@@ -2801,6 +2826,7 @@ for (;;)
+
+ local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+ local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
++ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE);
+ rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
+
+ while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
+@@ -2900,6 +2926,7 @@ for (;;)
+
+ local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+ local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
++ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE);
+ rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
+
+ while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
+@@ -2951,6 +2978,7 @@ for (;;)
+
+ local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+ local_workspace = ((int *)local_offsets) + RWS_OVEC_RSIZE;
++ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_RSIZE);
+ rws->free -= RWS_RSIZE + RWS_OVEC_RSIZE;
+
+ /* Check for repeating a recursion without advancing the subject
+@@ -3050,6 +3078,7 @@ for (;;)
+
+ local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+ local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
++ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE);
+ rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
+
+ if (codevalue == OP_BRAPOSZERO)
+@@ -3149,6 +3178,7 @@ for (;;)
+
+ local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+ local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
++ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE);
+ rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
+
+ rc = internal_dfa_match(
+diff --git a/testdata/testinput6 b/testdata/testinput6
+index f6f5cbf4..197f6f76 100644
+--- a/testdata/testinput6
++++ b/testdata/testinput6
+@@ -5263,4 +5263,11 @@
+ abc\=replace=xyz
+ abc\=replace=xyz,substitute_matched
+
++# --------------
++
++# Test workspace resizing and workspace re-use
++
++/(*LIMIT_HEAP=4)(?=(?=(?=(?=(?=(?=(?=(?=a))(?R)))))))./
++ a\=dfa
++
+ # End of testinput6
+diff --git a/testdata/testoutput6 b/testdata/testoutput6
+index 8ecf0040..4316c8a6 100644
+--- a/testdata/testoutput6
++++ b/testdata/testoutput6
+@@ -8237,4 +8237,12 @@ Failed: error -42: pattern contains an item that is not supported for DFA matchi
+ abc\=replace=xyz,substitute_matched
+ Failed: error -41: function is not supported for DFA matching
+
++# --------------
++
++# Test workspace resizing and workspace re-use
++
++/(*LIMIT_HEAP=4)(?=(?=(?=(?=(?=(?=(?=(?=a))(?R)))))))./
++ a\=dfa
++Failed: error -63: heap limit exceeded
++
+ # End of testinput6
diff --git a/patches/pcre2-10.48-Fix-JIT-STR_END.patch b/patches/pcre2-10.48-Fix-JIT-STR_END.patch
new file mode 100644
index 0000000..3761004
--- /dev/null
+++ b/patches/pcre2-10.48-Fix-JIT-STR_END.patch
@@ -0,0 +1,34 @@
+commit ff92e0b9cea5b5ae3af12ba930d03556684f098b
+Author: Zoltan Herczeg
+Date: Thu May 21 05:56:00 2026 +0200
+
+ Fix setting STR_END in JIT (#912)
+
+ When OP_VREVERSE is present in a non-atomic LOOKBEHIND ASSERTION,
+ the STR_END must be set before the backtracking path is executed.
+
+diff --git a/src/pcre2_jit_compile.c b/src/pcre2_jit_compile.c
+index 5d8c1c14..9013b686 100644
+--- a/src/pcre2_jit_compile.c
++++ b/src/pcre2_jit_compile.c
+@@ -12520,6 +12520,8 @@ else if (SLJIT_UNLIKELY(opcode == OP_ASSERT_SCS))
+ if (common->restore_end_ptr == 0)
+ common->restore_end_ptr = private_data_ptr + sizeof(sljit_sw);
+ }
++else if (SLJIT_UNLIKELY(opcode == OP_ASSERTBACK_NA) && PRIVATE_DATA(ccbegin + 1))
++ OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+
+ if (SLJIT_UNLIKELY(opcode == OP_ONCE))
+ {
+diff --git a/src/pcre2_jit_test.c b/src/pcre2_jit_test.c
+index 03cc348b..7c4bcd68 100644
+--- a/src/pcre2_jit_test.c
++++ b/src/pcre2_jit_test.c
+@@ -657,6 +657,7 @@ static struct regression_test_case regression_test_cases[] = {
+ { MU, A, 0, 0 | F_NOMATCH, "a(?!)b", "ab" },
+ { MU, A, 0, 0, "(?(?
+Date: Sat Aug 8 19:17:36 2026 +0100
+
+ Fix leak & stale PCRE2_MD_COPIED_SUBJECT if pcre2_jit_match used with existing match context (#937)
+
+ The problem is not that pcre2_jit_match() needs to add support for PCRE2_COPY_MATCHED_SUBJECT. Instead, if the passed-in context somehow contains a previously-copied subject (by non-JIT matcher using a global or cached subject) then it will be leaked, and worse, incorrectly free'd later.
+
+diff --git a/doc/html/pcre2jit.html b/doc/html/pcre2jit.html
+index cc26cc06..4e6d31e5 100644
+--- a/doc/html/pcre2jit.html
++++ b/doc/html/pcre2jit.html
+@@ -460,10 +460,11 @@ processed by pcre2_jit_compile()).
+ The fast path function is called pcre2_jit_match(), and it takes exactly
+ the same arguments as pcre2_match(). However, the subject string must be
+ specified with a length; PCRE2_ZERO_TERMINATED is not supported. Unsupported
+-option bits (for example, PCRE2_ANCHORED and PCRE2_ENDANCHORED) are ignored, as
+-is the PCRE2_NO_JIT option. The return values are also the same as for
+-pcre2_match(), plus PCRE2_ERROR_JIT_BADOPTION if a matching mode (partial
+-or complete) is requested that was not compiled.
++option bits (for example, PCRE2_ANCHORED, PCRE2_ENDANCHORED, and
++PCRE2_COPY_MATCHED_SUBJECT) are ignored, as is the PCRE2_NO_JIT option. The
++return values are also the same as for pcre2_match(), plus
++PCRE2_ERROR_JIT_BADOPTION if a matching mode (partial or complete) is requested
++that was not compiled.
+
+
+ When you call pcre2_match(), as well as testing for invalid options, a
+diff --git a/doc/pcre2.txt b/doc/pcre2.txt
+index 693908ee..cc316178 100644
+--- a/doc/pcre2.txt
++++ b/doc/pcre2.txt
+@@ -6194,11 +6194,11 @@ JIT FAST PATH API
+ The fast path function is called pcre2_jit_match(), and it takes ex-
+ actly the same arguments as pcre2_match(). However, the subject string
+ must be specified with a length; PCRE2_ZERO_TERMINATED is not sup-
+- ported. Unsupported option bits (for example, PCRE2_ANCHORED and
+- PCRE2_ENDANCHORED) are ignored, as is the PCRE2_NO_JIT option. The re-
+- turn values are also the same as for pcre2_match(), plus PCRE2_ER-
+- ROR_JIT_BADOPTION if a matching mode (partial or complete) is requested
+- that was not compiled.
++ ported. Unsupported option bits (for example, PCRE2_ANCHORED, PCRE2_EN-
++ DANCHORED, and PCRE2_COPY_MATCHED_SUBJECT) are ignored, as is the
++ PCRE2_NO_JIT option. The return values are also the same as for
++ pcre2_match(), plus PCRE2_ERROR_JIT_BADOPTION if a matching mode (par-
++ tial or complete) is requested that was not compiled.
+
+ When you call pcre2_match(), as well as testing for invalid options, a
+ number of other sanity checks are performed on the arguments. For exam-
+diff --git a/doc/pcre2jit.3 b/doc/pcre2jit.3
+index 95451b56..729d898f 100644
+--- a/doc/pcre2jit.3
++++ b/doc/pcre2jit.3
+@@ -444,10 +444,11 @@ processed by \fBpcre2_jit_compile()\fP).
+ The fast path function is called \fBpcre2_jit_match()\fP, and it takes exactly
+ the same arguments as \fBpcre2_match()\fP. However, the subject string must be
+ specified with a length; PCRE2_ZERO_TERMINATED is not supported. Unsupported
+-option bits (for example, PCRE2_ANCHORED and PCRE2_ENDANCHORED) are ignored, as
+-is the PCRE2_NO_JIT option. The return values are also the same as for
+-\fBpcre2_match()\fP, plus PCRE2_ERROR_JIT_BADOPTION if a matching mode (partial
+-or complete) is requested that was not compiled.
++option bits (for example, PCRE2_ANCHORED, PCRE2_ENDANCHORED, and
++PCRE2_COPY_MATCHED_SUBJECT) are ignored, as is the PCRE2_NO_JIT option. The
++return values are also the same as for \fBpcre2_match()\fP, plus
++PCRE2_ERROR_JIT_BADOPTION if a matching mode (partial or complete) is requested
++that was not compiled.
+ .P
+ When you call \fBpcre2_match()\fP, as well as testing for invalid options, a
+ number of other sanity checks are performed on the arguments. For example, if
+diff --git a/src/pcre2_jit_match_inc.h b/src/pcre2_jit_match_inc.h
+index 32d4c8a5..4163cf61 100644
+--- a/src/pcre2_jit_match_inc.h
++++ b/src/pcre2_jit_match_inc.h
+@@ -125,6 +125,16 @@ else if ((options & PCRE2_PARTIAL_SOFT) != 0)
+ if (functions == NULL || functions->executable_funcs[index] == NULL)
+ return match_data->rc = PCRE2_ERROR_JIT_BADOPTION;
+
++/* If the match data block was previously used with PCRE2_COPY_MATCHED_SUBJECT,
++free the memory that was obtained. */
++
++if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0)
++ {
++ match_data->memctl.free((void *)match_data->subject,
++ match_data->memctl.memory_data);
++ match_data->flags &= ~PCRE2_MD_COPIED_SUBJECT;
++ }
++
+ /* Sanity checks should be handled by pcre2_match. */
+ arguments.str = subject + start_offset;
+ arguments.begin = subject;
+diff --git a/src/pcre2test_inc.h b/src/pcre2test_inc.h
+index 5d282435..a74e3368 100644
+--- a/src/pcre2test_inc.h
++++ b/src/pcre2test_inc.h
+@@ -5199,20 +5199,28 @@ for (gmatched = 0;; gmatched++)
+ /* If PCRE2_COPY_MATCHED_SUBJECT was set, check that things are as they
+ should be, but not for fast JIT, where it isn't supported. */
+
+- if ((dat_datctl.options & PCRE2_COPY_MATCHED_SUBJECT) != 0 &&
+- (pat_patctl.control & CTL_JITFAST) == 0)
++ if ((dat_datctl.options & PCRE2_COPY_MATCHED_SUBJECT) != 0)
+ {
+- if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) == 0)
+- cfprintf(clr_test_error, outfile,
+- "** PCRE2 error: flag not set after copy_matched_subject\n");
++ if ((pat_patctl.control & CTL_JITFAST) != 0)
++ {
++ if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0)
++ cfprintf(clr_test_error, outfile,
++ "** PCRE2 error: flag set after unsupported copy_matched_subject\n");
++ }
++ else
++ {
++ if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) == 0)
++ cfprintf(clr_test_error, outfile,
++ "** PCRE2 error: flag not set after copy_matched_subject\n");
+
+- if (match_data->subject == pp)
+- cfprintf(clr_test_error, outfile,
+- "** PCRE2 error: copy_matched_subject has not copied\n");
++ if (match_data->subject == pp)
++ cfprintf(clr_test_error, outfile,
++ "** PCRE2 error: copy_matched_subject has not copied\n");
+
+- if (memcmp(match_data->subject, pp, ulen) != 0)
+- cfprintf(clr_test_error, outfile,
+- "** PCRE2 error: copy_matched_subject mismatch\n");
++ if (memcmp(match_data->subject, pp, ulen) != 0)
++ cfprintf(clr_test_error, outfile,
++ "** PCRE2 error: copy_matched_subject mismatch\n");
++ }
+ }
+
+ /* If this is not the first time round a global loop, check that the
+@@ -5689,6 +5697,9 @@ pcre2_match_context *test_dat_context = NULL, *test_dat_context_copy = NULL;
+ pcre2_convert_context *test_con_context = NULL, *test_con_context_copy = NULL;
+ pcre2_match_data *test_match_data = NULL;
+ pcre2_code *test_compiled_code = NULL;
++#ifdef SUPPORT_JIT
++BOOL test_compiled_with_jit = FALSE;
++#endif
+ PCRE2_UCHAR pattern[] = { CHAR_A, CHAR_B, CHAR_C, 0 };
+ PCRE2_UCHAR callout_int_pattern[] = {
+ CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK, CHAR_C, CHAR_RIGHT_PARENTHESIS, 0 };
+@@ -5993,11 +6004,38 @@ ASSERT(rc == 0 && sizeval == 0, "pcre2_pattern_info(JIT)");
+
+ if (pcre2_jit_compile(test_compiled_code, PCRE2_JIT_COMPLETE) == 0)
+ {
++ test_compiled_with_jit = TRUE;
++
+ rc = pcre2_pattern_info(test_compiled_code, PCRE2_INFO_JITSIZE, &sizeval);
+ ASSERT(rc == 0 && sizeval > 0, "pcre2_pattern_info(JIT after compile)");
+ }
+ #endif
+
++/* ----------------------- Matching functions ------------------------------ */
++
++#ifdef SUPPORT_JIT
++
++/* Check that fast JIT releases a copied subject when reusing match data. */
++if (test_compiled_with_jit)
++ {
++ test_match_data = pcre2_match_data_create_from_pattern(test_compiled_code,
++ test_gen_context);
++ ASSERT(test_match_data != NULL, "pcre2_match_data_create_from_pattern(JIT)");
++
++ rc = pcre2_match(test_compiled_code, pattern, 3, 0,
++ PCRE2_COPY_MATCHED_SUBJECT, test_match_data, NULL);
++ ASSERT(rc == 1, "pcre2_match(COPY_MATCHED_SUBJECT)");
++
++ rc = pcre2_jit_match(test_compiled_code, subject_abcz, 4, 0, 0,
++ test_match_data, NULL);
++ ASSERT(rc == 1, "pcre2_jit_match(reused match data)");
++
++ pcre2_match_data_free(test_match_data);
++ test_match_data = NULL;
++ }
++
++#endif
++
+ /* ----------------------- POSIX functions --------------------------------- */
+
+ #if PCRE2_CODE_UNIT_WIDTH == 8
+diff --git a/testdata/testinput17 b/testdata/testinput17
+index 08fd72e0..9d728965 100644
+--- a/testdata/testinput17
++++ b/testdata/testinput17
+@@ -298,6 +298,7 @@
+
+ /abc/jitfast
+ abc
++ abc\=copy_matched_subject
+ abc\=no_jit
+
+ # ----
+diff --git a/testdata/testoutput17 b/testdata/testoutput17
+index 6d550084..773ec18a 100644
+--- a/testdata/testoutput17
++++ b/testdata/testoutput17
+@@ -542,6 +542,8 @@ Failed: error -47: match limit exceeded
+
+ /abc/jitfast
+ abc
++ 0: abc (JIT)
++ abc\=copy_matched_subject
+ 0: abc (JIT)
+ abc\=no_jit
+ 0: abc (JIT)
+commit 1cad831209af67d24298c301a74c615d3a6d57eb
+Author: Carlo Marcelo Arenas Belón
+Date: Sat Aug 22 04:02:30 2026 -0700
+
+ pcre2test: honor no_jit when used with jitfast (#946)
+
+ `pcre2_jit_match()` ignores the PCRE2_NO_JIT option, so teach pcre2test
+ to avoid calling it if the subject modifier that sets that option is
+ used together with the option to call it directly.
+
+ While at it, make jitverify more reliable and add a unittest to validate
+ that PCRE2_NO_JIT is ignored in the fast JIt path.
+
+diff --git a/doc/html/pcre2test.html b/doc/html/pcre2test.html
+index 5160acc9..d2534780 100644
+--- a/doc/html/pcre2test.html
++++ b/doc/html/pcre2test.html
+@@ -863,7 +863,7 @@ when it can never be used.
+ The framesize modifier shows the size, in bytes, of each storage frame
+ used by pcre2_match() for handling backtracking. The size depends on the
+ number of capturing parentheses in the pattern. A vector of these frames is
+-used at matching time; its overall size is shown when the heaframes_size
++used at matching time; its overall size is shown when the heapframes_size
+ subject modifier is set.
+
+
+diff --git a/doc/pcre2test.1 b/doc/pcre2test.1
+index 897552a2..c5bc9317 100644
+--- a/doc/pcre2test.1
++++ b/doc/pcre2test.1
+@@ -811,7 +811,7 @@ when it can never be used.
+ The \fBframesize\fP modifier shows the size, in bytes, of each storage frame
+ used by \fBpcre2_match()\fP for handling backtracking. The size depends on the
+ number of capturing parentheses in the pattern. A vector of these frames is
+-used at matching time; its overall size is shown when the \fBheaframes_size\fP
++used at matching time; its overall size is shown when the \fBheapframes_size\fP
+ subject modifier is set.
+ .P
+ The \fBcallout_info\fP modifier requests information about all the callouts in
+diff --git a/doc/pcre2test.txt b/doc/pcre2test.txt
+index 819fe76e..fad3b8f3 100644
+--- a/doc/pcre2test.txt
++++ b/doc/pcre2test.txt
+@@ -787,7 +787,7 @@ PATTERN MODIFIERS
+ used by pcre2_match() for handling backtracking. The size depends on
+ the number of capturing parentheses in the pattern. A vector of these
+ frames is used at matching time; its overall size is shown when the
+- heaframes_size subject modifier is set.
++ heapframes_size subject modifier is set.
+
+ The callout_info modifier requests information about all the callouts
+ in the pattern. A list of them is output at the end of any other infor-
+diff --git a/src/pcre2test_inc.h b/src/pcre2test_inc.h
+index 72767916..69c64f73 100644
+--- a/src/pcre2test_inc.h
++++ b/src/pcre2test_inc.h
+@@ -3165,7 +3165,8 @@ for (;;)
+ dat_context, dfa_workspace, DFA_WS_DIMENSION);
+ }
+
+- else if ((pat_patctl.control & CTL_JITFAST) != 0)
++ else if ((pat_patctl.control & CTL_JITFAST) != 0 &&
++ (dat_datctl.options & PCRE2_NO_JIT) == 0)
+ capcount = pcre2_jit_match(compiled_code, pp, ulen, dat_datctl.offset,
+ dat_datctl.options, match_data, dat_context);
+
+@@ -4747,7 +4748,8 @@ if (dat_datctl.replacement[0] != MOD_STR_UNSET)
+ dat_datctl.offset, dat_datctl.options, match_data,
+ use_dat_context, dfa_workspace, DFA_WS_DIMENSION);
+ }
+- else if ((pat_patctl.control & CTL_JITFAST) != 0)
++ else if ((pat_patctl.control & CTL_JITFAST) != 0 &&
++ (dat_datctl.options & PCRE2_NO_JIT) == 0)
+ {
+ (void)pcre2_jit_match(compiled_code, pp, arg_ulen, dat_datctl.offset,
+ dat_datctl.options, match_data, use_dat_context);
+@@ -4990,7 +4992,7 @@ for (gmatched = 0;; gmatched++)
+ /* When matching is via pcre2_match(), we will detect the use of JIT via the
+ stack callback function. */
+
+- jit_was_used = (pat_patctl.control & CTL_JITFAST) != 0;
++ jit_was_used = FALSE;
+
+ /* Do timing if required. */
+
+@@ -5021,7 +5023,8 @@ for (gmatched = 0;; gmatched++)
+ }
+ }
+
+- else if ((pat_patctl.control & CTL_JITFAST) != 0)
++ else if ((pat_patctl.control & CTL_JITFAST) != 0 &&
++ (dat_datctl.options & PCRE2_NO_JIT) == 0)
+ {
+ start_time = clock();
+ for (i = 0; i < timeitm; i++)
+@@ -5105,9 +5108,11 @@ for (gmatched = 0;; gmatched++)
+ }
+ else
+ {
+- if ((pat_patctl.control & CTL_JITFAST) != 0)
+- capcount = pcre2_jit_match(compiled_code, pp, arg_ulen, dat_datctl.offset,
+- dat_datctl.options | g_notempty, match_data, use_dat_context);
++ if ((pat_patctl.control & CTL_JITFAST) != 0 &&
++ (dat_datctl.options & PCRE2_NO_JIT) == 0)
++ capcount = pcre2_jit_match(compiled_code, pp, arg_ulen,
++ dat_datctl.offset, dat_datctl.options | g_notempty, match_data,
++ use_dat_context);
+ else
+ capcount = pcre2_match(compiled_code, pp, arg_ulen, dat_datctl.offset,
+ dat_datctl.options | g_notempty, match_data, use_dat_context);
+@@ -5142,12 +5147,15 @@ for (gmatched = 0;; gmatched++)
+ }
+ else
+ {
+- if ((pat_patctl.control & CTL_JITFAST) != 0)
+- capcount = pcre2_jit_match(compiled_code, pp, arg_ulen, dat_datctl.offset,
+- dat_datctl.options | g_notempty, match_data, use_dat_context);
++ if ((pat_patctl.control & CTL_JITFAST) != 0 &&
++ (dat_datctl.options & PCRE2_NO_JIT) == 0)
++ capcount = pcre2_jit_match(compiled_code, pp, arg_ulen,
++ dat_datctl.offset, dat_datctl.options | g_notempty, match_data,
++ use_dat_context);
+ else
+- capcount = pcre2_match(compiled_code, pp, arg_ulen, dat_datctl.offset,
+- dat_datctl.options | g_notempty, match_data, use_dat_context);
++ capcount = pcre2_match(compiled_code, pp, arg_ulen,
++ dat_datctl.offset, dat_datctl.options | g_notempty, match_data,
++ use_dat_context);
+ }
+
+ mallocs_until_failure = INT_MAX;
+@@ -5207,12 +5215,20 @@ for (gmatched = 0;; gmatched++)
+ return PR_ABEND;
+ }
+
++ /* tracking JIT with jitverify needs a context, but in cases where one
++ wasn't available, can fallback to the match_data status */
++
++ if ((dat_datctl.control & CTL_NULLCONTEXT) != 0 &&
++ (pat_patctl.control & CTL_JITVERIFY) != 0)
++ jit_was_used = match_data->matchedby == PCRE2_MATCHEDBY_JIT;
++
+ /* If PCRE2_COPY_MATCHED_SUBJECT was set, check that things are as they
+ should be, but not for fast JIT, where it isn't supported. */
+
+ if ((dat_datctl.options & PCRE2_COPY_MATCHED_SUBJECT) != 0)
+ {
+- if ((pat_patctl.control & CTL_JITFAST) != 0)
++ if ((pat_patctl.control & CTL_JITFAST) != 0 &&
++ (dat_datctl.options & PCRE2_NO_JIT) == 0)
+ {
+ if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0)
+ cfprintf(clr_test_error, outfile,
+@@ -6026,9 +6042,11 @@ if (pcre2_jit_compile(test_compiled_code, PCRE2_JIT_COMPLETE) == 0)
+
+ #ifdef SUPPORT_JIT
+
+-/* Check that fast JIT releases a copied subject when reusing match data. */
+ if (test_compiled_with_jit)
+ {
++
++/* Check that fast JIT releases a copied subject when reusing match data. */
++
+ test_match_data = pcre2_match_data_create_from_pattern(test_compiled_code,
+ test_gen_context);
+ ASSERT(test_match_data != NULL, "pcre2_match_data_create_from_pattern(JIT)");
+@@ -6043,6 +6061,22 @@ if (test_compiled_with_jit)
+
+ pcre2_match_data_free(test_match_data);
+ test_match_data = NULL;
++
++/* Check that fast JIT ignores PCRE2_NO_JIT */
++
++ test_match_data = pcre2_match_data_create(100000, test_gen_context);
++ ASSERT(test_match_data != NULL, "pcre2_match_data_create(100000)");
++ ASSERT(pcre2_get_ovector_count(test_match_data) == 65535,
++ "pcre2_get_ovector_count(UINT32_MAX) <= UINT16_MAX)");
++
++ rc = pcre2_jit_match(test_compiled_code, subject_abcz, 4, 0, PCRE2_NO_JIT,
++ test_match_data, NULL);
++ ASSERT(rc == 1 && (test_match_data->matchedby == PCRE2_MATCHEDBY_JIT),
++ "pcre2_jit_match(ignore PCRE2_NO_JIT");
++
++ pcre2_match_data_free(test_match_data);
++ test_match_data = NULL;
++
+ }
+
+ #endif
+diff --git a/testdata/testinput17 b/testdata/testinput17
+index e6dbbe42..a02e6be2 100644
+--- a/testdata/testinput17
++++ b/testdata/testinput17
+@@ -295,12 +295,29 @@
+ /abc/
+ abc
+ abc\=no_jit
+-
++
++/(*NO_JIT)abc/
++ abc
++
+ /abc/jitfast
+ abc
+- abc\=copy_matched_subject
+ abc\=no_jit
+-
++
++/(*NO_JIT)abc/jitfast
++\= Expect error
++ abc
++
++# Do not leak a previously copied subject with jitfast (#920)
++
++/abc/jitfast
++ abc\=copy_matched_subject,no_jit
++ abc
++
++/abc/jitfast
++ abc\=copy_matched_subject
++ abc\=null_context
++ abc\=null_context,no_jit
++
+ # ----
+
+ /[aC]/mg,firstline,newline=lf
+diff --git a/testdata/testoutput17 b/testdata/testoutput17
+index 11f032d8..c678587f 100644
+--- a/testdata/testoutput17
++++ b/testdata/testoutput17
+@@ -539,15 +539,38 @@ Failed: error -47: match limit exceeded
+ 0: abc (JIT)
+ abc\=no_jit
+ 0: abc
+-
++
++/(*NO_JIT)abc/
++ abc
++ 0: abc
++
++/abc/jitfast
++ abc
++ 0: abc (JIT)
++ abc\=no_jit
++ 0: abc
++
++/(*NO_JIT)abc/jitfast
++\= Expect error
++ abc
++Failed: error -45: bad JIT option
++
++# Do not leak a previously copied subject with jitfast (#920)
++
+ /abc/jitfast
++ abc\=copy_matched_subject,no_jit
++ 0: abc
+ abc
+ 0: abc (JIT)
++
++/abc/jitfast
+ abc\=copy_matched_subject
+ 0: abc (JIT)
+- abc\=no_jit
++ abc\=null_context
+ 0: abc (JIT)
+-
++ abc\=null_context,no_jit
++ 0: abc
++
+ # ----
+
+ /[aC]/mg,firstline,newline=lf
diff --git a/patches/pcre2-10.48-Fix-allocation-byte-sizing.patch b/patches/pcre2-10.48-Fix-allocation-byte-sizing.patch
new file mode 100644
index 0000000..98295d8
--- /dev/null
+++ b/patches/pcre2-10.48-Fix-allocation-byte-sizing.patch
@@ -0,0 +1,54 @@
+commit 8156b3989a82f2ddf9504d8248496e9b124be7f3
+Author: Ilia Alshanetsky
+Date: Sun Aug 9 07:15:03 2026 -0400
+
+ Use CU2BYTES for byte sizing in two allocation sites (#909)
+
+ Two allocation sites multiplied by PCRE2_CODE_UNIT_WIDTH (the bit width:
+ 8, 16, or 32) where the CU2BYTES(x) byte-count helper is intended. The
+ result over-allocates by the code-unit byte width: 8x in 8-bit mode, 16x
+ in 16-bit, 32x in 32-bit. Subsequent memcpy calls already use CU2BYTES
+ correctly, so no out-of-bounds write occurs; the over-allocation is
+ leaked until the buffer is freed.
+
+ Also guard each site against integer overflow in
+ sizeof(pcre2_memctl) + CU2BYTES(N + 1) by rejecting N greater than
+ (PCRE2_SIZE_MAX - sizeof(pcre2_memctl)) / CU2BYTES(1) - 1.
+
+diff --git a/src/pcre2_convert.c b/src/pcre2_convert.c
+index ad7312ab..8a2b293d 100644
+--- a/src/pcre2_convert.c
++++ b/src/pcre2_convert.c
+@@ -1215,9 +1215,11 @@ for (int i = 0; i < 2; i++)
+ /* Allocate memory for the buffer, with hidden space for an allocator at
+ the start. The next time round the loop runs the conversion for real. */
+
+- allocated = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
+- (*bufflenptr + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)ccontext);
+- if (allocated == NULL)
++ if (*bufflenptr > ((PCRE2_SIZE_MAX - sizeof(pcre2_memctl)) /
++ CU2BYTES(1)) - 1 ||
++ (allocated = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
++ CU2BYTES(*bufflenptr + 1),
++ (pcre2_memctl *)ccontext)) == NULL)
+ {
+ *bufflenptr = 0; /* Error offset */
+ return PCRE2_ERROR_NOMEMORY;
+diff --git a/src/pcre2_substring.c b/src/pcre2_substring.c
+index f68b464e..a6f5277a 100644
+--- a/src/pcre2_substring.c
++++ b/src/pcre2_substring.c
+@@ -210,9 +210,10 @@ PCRE2_SIZE size;
+ PCRE2_UCHAR *yield;
+ rc = pcre2_substring_length_bynumber(match_data, stringnumber, &size);
+ if (rc < 0) return rc;
+-yield = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
+- (size + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)match_data);
+-if (yield == NULL) return PCRE2_ERROR_NOMEMORY;
++if (size > ((PCRE2_SIZE_MAX - sizeof(pcre2_memctl)) / CU2BYTES(1)) - 1 ||
++ (yield = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
++ CU2BYTES(size + 1), (pcre2_memctl *)match_data)) == NULL)
++ return PCRE2_ERROR_NOMEMORY;
+ yield = (PCRE2_UCHAR *)(((char *)yield) + sizeof(pcre2_memctl));
+ if (size != 0) memcpy(yield, match_data->subject + match_data->ovector[stringnumber*2],
+ CU2BYTES(size));
diff --git a/patches/pcre2-10.48-Fix-character-list-generator.patch b/patches/pcre2-10.48-Fix-character-list-generator.patch
new file mode 100644
index 0000000..6db9a28
--- /dev/null
+++ b/patches/pcre2-10.48-Fix-character-list-generator.patch
@@ -0,0 +1,113 @@
+commit f483bce249c537c482d686234257017dcfb72aaf
+Author: Zoltan Herczeg
+Date: Tue Nov 18 15:19:41 2025 +0100
+
+ Fix character list generator (#841)
+
+diff --git a/src/pcre2_compile_class.c b/src/pcre2_compile_class.c
+index 55b641c1..c6f30d6f 100644
+--- a/src/pcre2_compile_class.c
++++ b/src/pcre2_compile_class.c
+@@ -721,9 +721,13 @@ while (TRUE)
+ else
+ cranges->char_lists_types |= tmp1 << tmp2;
+
+- if (range_start < XCL_CHAR_LIST_LOW_16_START) break;
++ if (range_end < XCL_CHAR_LIST_LOW_16_START || tmp2 == 0)
++ {
++ PCRE2_ASSERT(range_start < XCL_CHAR_LIST_LOW_16_START);
++ break;
++ }
+
+- PCRE2_ASSERT(tmp2 >= XCL_TYPE_BIT_LEN);
++ PCRE2_ASSERT((tmp2 % XCL_TYPE_BIT_LEN) == 0);
+ char_list_end = char_list_start - 1;
+ char_list_start = *char_list_next++;
+ tmp1 = 0;
+diff --git a/src/pcre2_internal.h b/src/pcre2_internal.h
+index aa794095..2675e58e 100644
+--- a/src/pcre2_internal.h
++++ b/src/pcre2_internal.h
+@@ -1518,7 +1518,7 @@ High16 and High32: the highest bit is always one
+ The items are ordered in increasing order, so binary search can be
+ used to find the lower bound of an input character. The lower bound
+ is the highest item, which value is less or equal than the input
+-character. If the lower bit of the item is cleard, or the character
++character. If the lower bit of the item is cleared, or the character
+ stored in the item equals to the input character, the input
+ character is in the character list. */
+
+@@ -1539,14 +1539,19 @@ character is in the character list. */
+ #define XCL_CHAR_LIST_HIGH_32_END 0xffffffff
+ #define XCL_CHAR_LIST_HIGH_32_ADD 0x80000000
+
+-/* Mask for getting the descriptors of character list ranges.
+-Each descriptor has XCL_TYPE_BIT_LEN bits, and can be processed
+-by XCL_BEGIN_WITH_RANGE and XCL_ITEM_COUNT_MASK macros. */
++/* Mask and length values for getting the descriptors of
++all character list ranges. The bit length of each descriptor
++is XCL_TYPE_BIT_LEN so the total size is 4*XCL_TYPE_BIT_LEN
++(currently 12 bit). This data is stored for all four character
++lists, even if no characters are present in a list. */
+ #define XCL_TYPE_MASK 0xfff
+ #define XCL_TYPE_BIT_LEN 3
+-/* If this bit is set, the first item of the character list is the
+-end of a range, which started before the starting character of the
+-character list. */
++/* If this bit is set for a character class, the first item of the
++character list is the end of a range, which started before the
++starting character of the character list. If this bit is set, and
++no characters are present in the list, the whole character class
++is part of a range. E.g: [\x{500}-\x{12000}] covers the entire
++0x8000-0xffff range. */
+ #define XCL_BEGIN_WITH_RANGE 0x4
+ /* Number of items in the character list: 0, 1, or 2. The value 3
+ represents that the item count is stored at the begining of the
+diff --git a/testdata/testinput5 b/testdata/testinput5
+index 7f9f6a2d..d47e0c1e 100644
+--- a/testdata/testinput5
++++ b/testdata/testinput5
+@@ -2892,6 +2892,12 @@
+ /([\x{6535}\x{6536}\x{6538}\x{6539}\x{653b}\x{653c}\x{653e}\x{653f}\x{6541}\x{6542}\x{8000}-\x{ffff}]#)+/B,utf
+ \x{6534}#\x{6537}#\x{653a}#\x{653d}#\x{6540}#\x{6543}#\x{7fff}#\x{6535}#\x{6536}#\x{6538}#\x{6539}#\x{653b}#\x{653c}#\x{653e}#\x{653f}#\x{6541}#\x{6542}#\x{8000}#\x{c246}#\x{ffff}
+
++/[\x{ff}\x{100}\x{8000}\x{8002}\x{8004}\x{8006}\x{8008}\x{800a}\x{800c}\x{800e}]+/B,utf
++ \x{ff}\x{100}\x{8000}\x{800a}\x{800e}\x{101}
++
++/[\x{ff}-\x{104}\x{8000}\x{8002}\x{8004}\x{8006}\x{8008}\x{800a}\x{800c}\x{800e}]+/B,utf
++ \x{ff}\x{100}\x{101}\x{104}\x{8000}\x{800a}\x{800e}\x{105}
++
+ /[[:xdigit:]\x{400}-\x{600}]+/utf,ucp
+ !a0\x{400}\x{600}9\x{3ff}
+
+diff --git a/testdata/testoutput5 b/testdata/testoutput5
+index fd36974d..82b3abe9 100644
+--- a/testdata/testoutput5
++++ b/testdata/testoutput5
+@@ -6339,6 +6339,26 @@ Failed: error 115 at offset 53: reference to non-existent subpattern
+ 0: \x{6535}#\x{6536}#\x{6538}#\x{6539}#\x{653b}#\x{653c}#\x{653e}#\x{653f}#\x{6541}#\x{6542}#\x{8000}#\x{c246}#
+ 1: \x{c246}#
+
++/[\x{ff}\x{100}\x{8000}\x{8002}\x{8004}\x{8006}\x{8008}\x{800a}\x{800c}\x{800e}]+/B,utf
++------------------------------------------------------------------
++ Bra
++ [\xff\x{100}\x{8000}\x{8002}\x{8004}\x{8006}\x{8008}\x{800a}\x{800c}\x{800e}]++
++ Ket
++ End
++------------------------------------------------------------------
++ \x{ff}\x{100}\x{8000}\x{800a}\x{800e}\x{101}
++ 0: \x{ff}\x{100}\x{8000}\x{800a}\x{800e}
++
++/[\x{ff}-\x{104}\x{8000}\x{8002}\x{8004}\x{8006}\x{8008}\x{800a}\x{800c}\x{800e}]+/B,utf
++------------------------------------------------------------------
++ Bra
++ [\xff\x{100}-\x{104}\x{8000}\x{8002}\x{8004}\x{8006}\x{8008}\x{800a}\x{800c}\x{800e}]++
++ Ket
++ End
++------------------------------------------------------------------
++ \x{ff}\x{100}\x{101}\x{104}\x{8000}\x{800a}\x{800e}\x{105}
++ 0: \x{ff}\x{100}\x{101}\x{104}\x{8000}\x{800a}\x{800e}
++
+ /[[:xdigit:]\x{400}-\x{600}]+/utf,ucp
+ !a0\x{400}\x{600}9\x{3ff}
+ 0: a0\x{400}\x{600}9
diff --git a/patches/pcre2-10.48-Fix-compiler-integer-overflows.patch b/patches/pcre2-10.48-Fix-compiler-integer-overflows.patch
new file mode 100644
index 0000000..53ee06e
--- /dev/null
+++ b/patches/pcre2-10.48-Fix-compiler-integer-overflows.patch
@@ -0,0 +1,200 @@
+commit ec9c286d5c10cf1c388b58a442ccefded42254fd
+Author: Nicholas Wilson
+Date: Thu Aug 27 16:52:16 2026 +0100
+
+ Fix compiler integer overflows; see GHSA-fmgr-6ggq-9859 for details
+
+diff --git a/src/pcre2_compile.c b/src/pcre2_compile.c
+index 1081cf64..32cb32f6 100644
+--- a/src/pcre2_compile.c
++++ b/src/pcre2_compile.c
+@@ -6195,7 +6195,8 @@ for (;; pptr++)
+
+ if (meta < META_ASTERISK || meta > META_MINMAX_QUERY)
+ {
+- if (OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code))
++ if (*lengthptr > OFLOW_MAX ||
++ OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code))
+ {
+ *errorcodeptr = ERR20; /* Integer overflow */
+ cb->erroroffset = 0;
+@@ -8802,7 +8803,8 @@ for (;;)
+ *reqcuflagsptr = reqcuflags;
+ if (lengthptr != NULL)
+ {
+- if (OFLOW_MAX - *lengthptr < length)
++ if (*lengthptr > MAX_PATTERN_SIZE ||
++ MAX_PATTERN_SIZE - *lengthptr < length)
+ {
+ *errorcodeptr = ERR20;
+ return 0;
+@@ -8825,6 +8827,19 @@ for (;;)
+ {
+ code = *codeptr + 1 + LINK_SIZE + skipunits;
+ length += 1 + LINK_SIZE;
++
++ /* Move the accumulated length into *lengthptr, providing the next call to
++ compile_branch with as much space in &length and &code as the first did. */
++
++ if (*lengthptr > MAX_PATTERN_SIZE ||
++ MAX_PATTERN_SIZE - *lengthptr < length)
++ {
++ *errorcodeptr = ERR20;
++ cb->erroroffset = 0;
++ return 0;
++ }
++ *lengthptr += length;
++ length = 0;
+ }
+ else
+ {
+@@ -10851,7 +10866,8 @@ if (errorcode != 0) goto HAD_CB_ERROR; /* Offset is in cb.erroroffset */
+ #if defined SUPPORT_WIDE_CHARS
+ PCRE2_ASSERT((cb.char_lists_size & 0x3) == 0);
+ if (length > MAX_PATTERN_SIZE ||
+- MAX_PATTERN_SIZE - length < (cb.char_lists_size / sizeof(PCRE2_UCHAR)))
++ BYTES2CU(cb.char_lists_size) > MAX_PATTERN_SIZE ||
++ MAX_PATTERN_SIZE - length < BYTES2CU(cb.char_lists_size))
+ #else
+ if (length > MAX_PATTERN_SIZE)
+ #endif
+@@ -10876,11 +10892,36 @@ if (cb.char_lists_size != 0)
+ /* Align to 32 bit first. This ensures the
+ allocated area will also be 32 bit aligned. */
+ re_blocksize = (PCRE2_SIZE)CLIST_ALIGN_TO(re_blocksize, sizeof(uint32_t));
++#else
++ /* Already 32 bit aligned. */
+ #endif
++
++ /* We have bounded the length and BYTES2CU(char_lists_size) to
++ MAX_PATTERN_SIZE units, however (with 32-bit code units) char_lists_size
++ in bytes could still be extremely close to (or greater than) SIZE_MAX, so
++ we require another overflow check. */
++
++ if (cb.char_lists_size > PCRE2_SIZE_MAX - re_blocksize)
++ {
++ errorcode = ERR20;
++ cb.erroroffset = 0;
++ goto HAD_CB_ERROR;
++ }
++
+ re_blocksize += cb.char_lists_size;
+ }
+ #endif
+
++if (length > BYTES2CU(PCRE2_SIZE_MAX - re_blocksize))
++ {
++ /* Given the current value of 2^30 for MAX_PATTERN_SIZE, this block is only
++ reachable when both PCRE2_CODE_UNIT_WIDTH >= 16 and sizeof(size_t) is
++ 32 bits. */
++ errorcode = ERR20;
++ cb.erroroffset = 0;
++ goto HAD_CB_ERROR;
++ }
++
+ re_blocksize += CU2BYTES(length);
+
+ if (re_blocksize > ccontext->max_pattern_compiled_length)
+@@ -10890,7 +10931,15 @@ if (re_blocksize > ccontext->max_pattern_compiled_length)
+ goto HAD_CB_ERROR;
+ }
+
++if (sizeof(pcre2_real_code) > PCRE2_SIZE_MAX - re_blocksize)
++ {
++ errorcode = ERR20;
++ cb.erroroffset = 0;
++ goto HAD_CB_ERROR;
++ }
++
+ re_blocksize += sizeof(pcre2_real_code);
++
+ re = (pcre2_real_code *)
+ ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data);
+ if (re == NULL)
+diff --git a/src/pcre2_compile_class.c b/src/pcre2_compile_class.c
+index c6f30d6f..c0606643 100644
+--- a/src/pcre2_compile_class.c
++++ b/src/pcre2_compile_class.c
+@@ -498,7 +498,7 @@ static const uint32_t char_list_starts[] = {
+
+ static class_ranges *
+ compile_optimize_class(uint32_t *start_ptr, uint32_t options,
+- uint32_t xoptions, compile_block *cb)
++ uint32_t xoptions, int *errorcodeptr, compile_block *cb)
+ {
+ class_ranges* cranges;
+ uint32_t *ptr;
+@@ -538,12 +538,23 @@ PCRE2_ASSERT((range_list_size & 0x1) == 0);
+
+ total_size = range_list_size +
+ ((range_list_size >= 2) ? CHAR_LIST_EXTRA_SIZE : 0);
++if (total_size > (PCRE2_SIZE_MAX - sizeof(class_ranges)) / sizeof(uint32_t))
++ {
++ *errorcodeptr = ERR20;
++ cb->erroroffset = 0;
++ return NULL;
++ }
+
+ cranges = cb->cx->memctl.malloc(
+ sizeof(class_ranges) + total_size * sizeof(uint32_t),
+ cb->cx->memctl.memory_data);
+
+-if (cranges == NULL) return NULL;
++if (cranges == NULL)
++ {
++ *errorcodeptr = ERR21;
++ cb->erroroffset = 0;
++ return NULL;
++ }
+
+ cranges->header.next = NULL;
+ #ifdef PCRE2_DEBUG
+@@ -1120,13 +1131,10 @@ if (utf)
+ {
+ if (lengthptr != NULL)
+ {
+- cranges = compile_optimize_class(pptr, options, xoptions, cb);
++ cranges = compile_optimize_class(pptr, options, xoptions, errorcodeptr, cb);
+
+ if (cranges == NULL)
+- {
+- *errorcodeptr = ERR21;
+ return NULL;
+- }
+
+ /* Caching the pre-processed character ranges. */
+ if (cb->last_data != NULL)
+@@ -1759,18 +1767,17 @@ if ((xclass_props & XCLASS_REQUIRED) != 0)
+ *lengthptr += 1 + LINK_SIZE;
+ #endif
+
+- cb->char_lists_size += char_lists_size;
+-
+- char_lists_size /= sizeof(PCRE2_UCHAR);
++ PCRE2_ASSERT(BYTES2CU(cb->char_lists_size) <= MAX_PATTERN_SIZE);
+
+- /* Storage space for character lists is included
+- in the maximum pattern size. */
+- if (*lengthptr > MAX_PATTERN_SIZE ||
+- MAX_PATTERN_SIZE - *lengthptr < char_lists_size)
++ if (char_lists_size > PCRE2_SIZE_MAX - cb->char_lists_size ||
++ BYTES2CU(char_lists_size) > MAX_PATTERN_SIZE ||
++ BYTES2CU(cb->char_lists_size) > MAX_PATTERN_SIZE - BYTES2CU(char_lists_size))
+ {
+ *errorcodeptr = ERR20; /* Pattern is too large */
+ return NULL;
+ }
++
++ cb->char_lists_size += char_lists_size;
+ }
+ else
+ {
+@@ -1793,6 +1800,8 @@ if ((xclass_props & XCLASS_REQUIRED) != 0)
+ Each list is aligned to 32 bit with an optional unused
+ 16 bit value at the beginning of the character list. */
+
++ PCRE2_ASSERT(char_lists_size <= PCRE2_SIZE_MAX - cb->char_lists_size);
++
+ cb->char_lists_size += char_lists_size;
+ data = (uint8_t*)cb->start_code - cb->char_lists_size;
+
diff --git a/patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch b/patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch
new file mode 100644
index 0000000..5a4170a
--- /dev/null
+++ b/patches/pcre2-10.48-Fix-invalid-UTF-backwards-scans.patch
@@ -0,0 +1,212 @@
+commit 4889caf31a4c5a6b3c051f0031bf2dbd78f2c287
+Author: Nicholas Wilson
+Date: Thu Aug 27 16:52:16 2026 +0100
+
+ Fix invalid UTF backwards-scan reads; see GHSA-9qww-pwc4-77qq for details
+
+diff --git a/src/pcre2_extuni.c b/src/pcre2_extuni.c
+index 1b7f04b4..fea098a7 100644
+--- a/src/pcre2_extuni.c
++++ b/src/pcre2_extuni.c
+@@ -54,12 +54,12 @@ support, because some compilers do not like functionless source files. */
+
+ #ifndef SUPPORT_UNICODE
+ PCRE2_SPTR
+-PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject,
++PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR check_subject,
+ PCRE2_SPTR end_subject, BOOL utf, int *xcount)
+ {
+ (void)c;
+ (void)eptr;
+-(void)start_subject;
++(void)check_subject;
+ (void)end_subject;
+ (void)utf;
+ (void)xcount;
+@@ -80,7 +80,7 @@ same behaviour.
+ Arguments:
+ c the first character
+ eptr pointer to next character
+- start_subject pointer to start of subject
++ check_subject pointer to start of validated subject
+ end_subject pointer to end of subject
+ utf TRUE if in UTF mode
+ xcount pointer to count of additional characters,
+@@ -90,7 +90,7 @@ Returns: pointer after the end of the sequence
+ */
+
+ PCRE2_SPTR
+-PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject,
++PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR check_subject,
+ PCRE2_SPTR end_subject, BOOL utf, int *xcount)
+ {
+ BOOL was_ep_ZWJ = FALSE;
+@@ -121,7 +121,7 @@ while (eptr < end_subject)
+
+ /* bptr is pointing to the left-hand character */
+
+- while (bptr > start_subject)
++ while (bptr > check_subject)
+ {
+ bptr--;
+ if (utf)
+diff --git a/src/pcre2_match.c b/src/pcre2_match.c
+index a5a8421f..966576e1 100644
+--- a/src/pcre2_match.c
++++ b/src/pcre2_match.c
+@@ -2895,7 +2895,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
+ else
+ {
+ GETCHARINCTEST(fc, Feptr);
+- Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject, utf,
++ Feptr = PRIV(extuni)(fc, Feptr, mb->check_subject, mb->end_subject, utf,
+ NULL);
+ }
+ CHECK_PARTIAL();
+@@ -3246,7 +3246,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
+ else
+ {
+ GETCHARINCTEST(fc, Feptr);
+- Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject,
++ Feptr = PRIV(extuni)(fc, Feptr, mb->check_subject,
+ mb->end_subject, utf, NULL);
+ }
+ CHECK_PARTIAL();
+@@ -4071,7 +4071,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
+ else
+ {
+ GETCHARINCTEST(fc, Feptr);
+- Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject,
++ Feptr = PRIV(extuni)(fc, Feptr, mb->check_subject, mb->end_subject,
+ utf, NULL);
+ }
+ CHECK_PARTIAL();
+@@ -4660,7 +4660,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
+ else
+ {
+ GETCHARINCTEST(fc, Feptr);
+- Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject,
++ Feptr = PRIV(extuni)(fc, Feptr, mb->check_subject, mb->end_subject,
+ utf, NULL);
+ }
+ CHECK_PARTIAL();
+@@ -6243,7 +6243,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
+ {
+ for (i = 0; i < Lmax; i++)
+ {
+- if (Feptr == mb->start_subject)
++ if (Feptr <= mb->check_subject)
+ {
+ if (i < Lmin) RRETURN(MATCH_NOMATCH);
+ Lmax = i;
+diff --git a/testdata/testinput10 b/testdata/testinput10
+index d9e6ba8c..bfa9dad8 100644
+--- a/testdata/testinput10
++++ b/testdata/testinput10
+@@ -585,6 +585,16 @@
+ AAA\x80BXYZ
+ AAA\x80BBXYZ
+
++# Backward scans must not enter the invalid prefix before check_subject.
++
++/(?<=a{1,2})X/utf,match_invalid_utf
++\= Expect no match
++ \x80X
++
++/\X\X/utf,match_invalid_utf
++\= Expect no match
++ \x80\x{1f1e6}\x{1f1e7}
++
+ /(?<=(.))/utf,match_invalid_utf
+ x\x80
+ \x{10000}\x80
+diff --git a/testdata/testinput12 b/testdata/testinput12
+index 01cc76a4..c4a89a26 100644
+--- a/testdata/testinput12
++++ b/testdata/testinput12
+@@ -498,6 +498,16 @@
+ /(..)(*scs:(1)ab$)/match_invalid_utf
+ ab\x{df00}cde
+
++# Backward scans must not enter the invalid prefix before check_subject.
++
++/(?<=a{1,2})X/utf,match_invalid_utf
++\= Expect no match
++ \x{dc00}X
++
++/\X\X/utf,match_invalid_utf
++\= Expect no match
++ \x{dc00}\x{1f1e6}\x{1f1e7}
++
+ /(?<=(.))/utf,match_invalid_utf
+ x\x{d800}
+ \x{10000}\x{dc00}
+diff --git a/testdata/testoutput10 b/testdata/testoutput10
+index 393ac207..9e124e2b 100644
+--- a/testdata/testoutput10
++++ b/testdata/testoutput10
+@@ -1779,6 +1779,18 @@ No match
+ AAA\x80BBXYZ
+ No match
+
++# Backward scans must not enter the invalid prefix before check_subject.
++
++/(?<=a{1,2})X/utf,match_invalid_utf
++\= Expect no match
++ \x80X
++No match
++
++/\X\X/utf,match_invalid_utf
++\= Expect no match
++ \x80\x{1f1e6}\x{1f1e7}
++No match
++
+ /(?<=(.))/utf,match_invalid_utf
+ x\x80
+ 0:
+diff --git a/testdata/testoutput12-16 b/testdata/testoutput12-16
+index d235c11f..b0676a19 100644
+--- a/testdata/testoutput12-16
++++ b/testdata/testoutput12-16
+@@ -1659,6 +1659,18 @@ No match
+ 0: ab
+ 1: ab
+
++# Backward scans must not enter the invalid prefix before check_subject.
++
++/(?<=a{1,2})X/utf,match_invalid_utf
++\= Expect no match
++ \x{dc00}X
++No match
++
++/\X\X/utf,match_invalid_utf
++\= Expect no match
++ \x{dc00}\x{1f1e6}\x{1f1e7}
++No match
++
+ /(?<=(.))/utf,match_invalid_utf
+ x\x{d800}
+ 0:
+diff --git a/testdata/testoutput12-32 b/testdata/testoutput12-32
+index 725cb274..a97051a6 100644
+--- a/testdata/testoutput12-32
++++ b/testdata/testoutput12-32
+@@ -1658,6 +1658,18 @@ No match
+ 0: ab
+ 1: ab
+
++# Backward scans must not enter the invalid prefix before check_subject.
++
++/(?<=a{1,2})X/utf,match_invalid_utf
++\= Expect no match
++ \x{dc00}X
++No match
++
++/\X\X/utf,match_invalid_utf
++\= Expect no match
++ \x{dc00}\x{1f1e6}\x{1f1e7}
++No match
++
+ /(?<=(.))/utf,match_invalid_utf
+ x\x{d800}
+ 0:
diff --git a/patches/pcre2-10.48-Fix-repeated-substitute-escapes.patch b/patches/pcre2-10.48-Fix-repeated-substitute-escapes.patch
new file mode 100644
index 0000000..265a374
--- /dev/null
+++ b/patches/pcre2-10.48-Fix-repeated-substitute-escapes.patch
@@ -0,0 +1,75 @@
+commit c07a6e8cdc2c2c0222d2441863df534b96377f35
+Author: Nicholas Wilson
+Date: Tue Dec 2 16:21:32 2025 +0000
+
+ Fix regression in handling of repeated backslash escapes in pcre2_substitute (#857)
+
+diff --git a/src/pcre2_substitute.c b/src/pcre2_substitute.c
+index fb187258..f323c56a 100644
+--- a/src/pcre2_substitute.c
++++ b/src/pcre2_substitute.c
+@@ -115,6 +115,7 @@ for (; ptr < ptrend; ptr++)
+ int erc;
+ int errorcode;
+ uint32_t ch;
++ PCRE2_SPTR esc_end_ptr;
+
+ if (ptr < ptrend - 1) switch (ptr[1])
+ {
+@@ -137,6 +138,9 @@ for (; ptr < ptrend; ptr++)
+ goto EXIT;
+ }
+
++ esc_end_ptr = ptr;
++ ptr -= 1; /* Rewind by one, because the for-loop will increment it */
++
+ switch(erc)
+ {
+ case 0: /* Data character */
+@@ -160,7 +164,8 @@ for (; ptr < ptrend; ptr++)
+
+ default:
+ if (erc < 0)
+- break; /* capture group reference */
++ break; /* capture group reference */
++ ptr = esc_end_ptr;
+ rc = PCRE2_ERROR_BADREPESCAPE;
+ goto EXIT;
+ }
+diff --git a/testdata/testinput2 b/testdata/testinput2
+index 8a905f58..e0cacced 100644
+--- a/testdata/testinput2
++++ b/testdata/testinput2
+@@ -8314,5 +8314,12 @@ a)"xI
+ foo|bar\=offset=1,substitute_subject=F|OOBAR,copy_matched_subject
+ foo|bar\=offset=1,substitute_subject=F|OOBAR,copy_matched_subject,zero_terminate
+
++# --------------
++# Some more tests for a substitution regression
++# --------------
++
++/foo(?BAR)?/substitute_extended,replace=X${Bar:+\:\:text}Y
++ foo
++ fooBAR
+
+ # End of testinput2
+diff --git a/testdata/testoutput2 b/testdata/testoutput2
+index 08e73823..bdd431e3 100644
+--- a/testdata/testoutput2
++++ b/testdata/testoutput2
+@@ -23656,6 +23656,15 @@ Failed: error -72: substitute subject differs from prior match call
+ foo|bar\=offset=1,substitute_subject=F|OOBAR,copy_matched_subject,zero_terminate
+ Failed: error -72: substitute subject differs from prior match call
+
++# --------------
++# Some more tests for a substitution regression
++# --------------
++
++/foo(?BAR)?/substitute_extended,replace=X${Bar:+\:\:text}Y
++ foo
++ 1: XY
++ fooBAR
++ 1: X::textY
+
+ # End of testinput2
+ Error -80: PCRE2_ERROR_BADDATA (unknown error number)
diff --git a/patches/pcre2-10.48-Fix-scan-prefix-repeat-reset.patch b/patches/pcre2-10.48-Fix-scan-prefix-repeat-reset.patch
new file mode 100644
index 0000000..470d590
--- /dev/null
+++ b/patches/pcre2-10.48-Fix-scan-prefix-repeat-reset.patch
@@ -0,0 +1,30 @@
+commit 7a33b226fe0dc243cbed47fcbe49025ec4aea125
+Author: Zoltan Herczeg
+Date: Sun Jan 25 06:38:11 2026 +0100
+
+ Fix repeat reset for scan prefix (#875)
+
+diff --git a/src/pcre2_jit_compile.c b/src/pcre2_jit_compile.c
+index 4cca50d4..5d8c1c14 100644
+--- a/src/pcre2_jit_compile.c
++++ b/src/pcre2_jit_compile.c
+@@ -6249,6 +6249,7 @@ while (TRUE)
+ repeat = GET2(cc, 1);
+ if (repeat <= 0)
+ {
++ repeat = 1;
+ chars_end = chars;
+ continue;
+ }
+diff --git a/src/pcre2_jit_test.c b/src/pcre2_jit_test.c
+index 1fc44db5..03cc348b 100644
+--- a/src/pcre2_jit_test.c
++++ b/src/pcre2_jit_test.c
+@@ -281,6 +281,7 @@ static struct regression_test_case regression_test_cases[] = {
+ { CM, A, 0, 0, "a1277|a1377|bx487", "bX487" },
+ { 0, A, 0, 0, "(a|)b*+a", "a" },
+ { 0, A, 0, 0 | F_NOMATCH, "(.|.|.|.|.)(|.|.|.|.)(.||.|.|.)(.|.||.|.)(.|.|.||.)(.|.|.|.|)(A|.|.|.|.)(.|A|.|.|.)(.|.|A|.|.)(.|.|.|A|.)(.|.|.|.|A)(B|.|.|.|.)(.|B|.|.|.)(.|.|B|.|.)(.|.|.|B|.)(.|.|.|.|B)xa", "1234567890123456ax" },
++ { 0, A, 0, 0, "(CHAN|LINE)[ab]{0,2}", "LINE" },
+
+ /* Greedy and non-greedy ? operators. */
+ { MU, A, 0, 0, "(?:a)?a", "laab" },
diff --git a/patches/pcre2-10.48-Keep-escape-error-offset-in-pattern.patch b/patches/pcre2-10.48-Keep-escape-error-offset-in-pattern.patch
new file mode 100644
index 0000000..83e4ab3
--- /dev/null
+++ b/patches/pcre2-10.48-Keep-escape-error-offset-in-pattern.patch
@@ -0,0 +1,92 @@
+commit c49915439a1fdfb97a8b6f8ae5676c18c5ac2eea
+Author: Kartik
+Date: Mon Aug 17 00:58:15 2026 +0530
+
+ Keep check_escape error offset within the pattern for \x{ and \o{ (#948)
+
+diff --git a/src/pcre2_compile.c b/src/pcre2_compile.c
+index c64fd273..aeda6370 100644
+--- a/src/pcre2_compile.c
++++ b/src/pcre2_compile.c
+@@ -2020,7 +2020,7 @@ else
+ else
+ {
+ *errorcodeptr = ERR64;
+- goto ESCAPE_FAILED_FORWARD;
++ if (ptr < ptrend) goto ESCAPE_FAILED_FORWARD;
+ }
+ break;
+
+@@ -2107,7 +2107,7 @@ else
+ else
+ {
+ *errorcodeptr = ERR67;
+- goto ESCAPE_FAILED_FORWARD;
++ if (ptr < ptrend) goto ESCAPE_FAILED_FORWARD;
+ }
+ } /* End of \x{} processing */
+
+diff --git a/testdata/testinput2 b/testdata/testinput2
+index 4bc71fcf..a7c1c846 100644
+--- a/testdata/testinput2
++++ b/testdata/testinput2
+@@ -3987,6 +3987,10 @@
+
+ /^A\x{/
+
++/\x{2/
++
++/\o{7/
++
+ /[ab]++/B,no_auto_possess
+
+ /[^ab]*+/B,no_auto_possess
+diff --git a/testdata/testinput5 b/testdata/testinput5
+index d47e0c1e..098f4100 100644
+--- a/testdata/testinput5
++++ b/testdata/testinput5
+@@ -3616,4 +3616,9 @@
+ \x{e1}
+ \x{c1}
+
++# An unterminated \N{U+ escape at the end of the pattern must
++# report an error offset that lies within the pattern.
++
++/(*UTF)\N{U+2/
++
+ # End of testinput5
+diff --git a/testdata/testoutput2 b/testdata/testoutput2
+index ccb5667f..acb4adf7 100644
+--- a/testdata/testoutput2
++++ b/testdata/testoutput2
+@@ -13630,6 +13630,14 @@ Failed: error 167 at offset 8: non-hex character in \x{} (closing brace missing?
+ Failed: error 178 at offset 5: digits missing after \x or in \x{} or \o{} or \N{U+}
+ here: ^A\x{ |<--|
+
++/\x{2/
++Failed: error 167 at offset 4: non-hex character in \x{} (closing brace missing?)
++ here: \x{2 |<--|
++
++/\o{7/
++Failed: error 164 at offset 4: non-octal character in \o{} (closing brace missing?)
++ here: \o{7 |<--|
++
+ /[ab]++/B,no_auto_possess
+ ------------------------------------------------------------------
+ Bra
+diff --git a/testdata/testoutput5 b/testdata/testoutput5
+index 82b3abe9..0337d6aa 100644
+--- a/testdata/testoutput5
++++ b/testdata/testoutput5
+@@ -8335,4 +8335,11 @@ Failed: error 150 at offset 5: invalid range in character class
+ \x{c1}
+ 0: \x{c1}
+
++# An unterminated \N{U+ escape at the end of the pattern must
++# report an error offset that lies within the pattern.
++
++/(*UTF)\N{U+2/
++Failed: error 167 at offset 12: non-hex character in \x{} (closing brace missing?)
++ here: ...UTF)\N{U+2 |<--|
++
+ # End of testinput5
diff --git a/patches/pcre2-10.48-Write-serialization-padding.patch b/patches/pcre2-10.48-Write-serialization-padding.patch
new file mode 100644
index 0000000..2546c0c
--- /dev/null
+++ b/patches/pcre2-10.48-Write-serialization-padding.patch
@@ -0,0 +1,80 @@
+commit edc111a6831591f68b5355a08cc9df8be8f35304
+Author: Nicholas Wilson
+Date: Sat Oct 25 10:50:27 2025 +0100
+
+ Write padding values to ensure pcre2_serialize_encode() outputs defined values (#826)
+
+ Fixes low-severity valgrind error reported in GHSA-q7rw-r7qq-2hx6.
+
+diff --git a/src/pcre2_compile_class.c b/src/pcre2_compile_class.c
+index 9a1fc022..55b641c1 100644
+--- a/src/pcre2_compile_class.c
++++ b/src/pcre2_compile_class.c
+@@ -1802,17 +1802,14 @@ if ((xclass_props & XCLASS_REQUIRED) != 0)
+ PUT(code, 0, (uint32_t)(char_lists_size >> 1));
+ code += LINK_SIZE;
+
+-#if defined PCRE2_DEBUG || defined SUPPORT_VALGRIND
++ /* If we added padding to align the list, initialize the bytes to
++ defined values, so the library is valgrind-clean. It could also
++ be a security concern for clients calling into PCRE2 via bindings
++ from a memory-safe language, if pcre2_serialize_encode() exposes
++ uninitialized memory that may contain sensitive information. */
++
+ if ((char_lists_size & 0x2) != 0)
+- {
+- /* In debug the unused 16 bit value is set
+- to a fixed value and marked unused. */
+- ((uint16_t*)data)[-1] = 0x5555;
+-#ifdef SUPPORT_VALGRIND
+- VALGRIND_MAKE_MEM_NOACCESS(data - 2, 2);
+-#endif
+- }
+-#endif
++ ((uint16_t*)data)[-1] = 0xdead;
+
+ cb->char_lists_size =
+ CLIST_ALIGN_TO(char_lists_size, sizeof(uint32_t));
+diff --git a/src/pcre2test_inc.h b/src/pcre2test_inc.h
+index 8124e9ca..c4707417 100644
+--- a/src/pcre2test_inc.h
++++ b/src/pcre2test_inc.h
+@@ -2019,6 +2019,9 @@ uint32_t use_forbid_utf = forbid_utf;
+ PCRE2_SIZE patlen, full_patlen;
+ PCRE2_SIZE valgrind_access_length;
+ PCRE2_SIZE erroroffset;
++int32_t serialize_rc;
++uint8_t *serialized_bytes;
++PCRE2_SIZE serialized_size;
+
+ /* The perltest.sh script supports only / as a delimiter. */
+
+@@ -2966,6 +2969,28 @@ if ((pat_patctl.control2 & CTL2_NL_SET) != 0)
+ rc = show_pattern_info();
+ if (rc != PR_OK) return rc;
+
++/* Verify that the compiled structure can be serialized without generating
++memory errors. */
++
++serialize_rc = pcre2_serialize_encode((const pcre2_code **)&compiled_code, 1,
++ &serialized_bytes, &serialized_size, general_context);
++if (serialize_rc != 1)
++ {
++ cfprintf(clr_test_error, outfile, "** pcre2_serialize_encode() returned %d instead of 1\n",
++ serialize_rc);
++ return PR_ABEND;
++ }
++
++#if defined SUPPORT_VALGRIND
++if (VALGRIND_CHECK_MEM_IS_DEFINED(serialized_bytes, serialized_size) != 0)
++ {
++ cfprintf(clr_test_error, outfile, "** pcre2_serialize_encode() returned undefined data\n");
++ return PR_ABEND;
++ }
++#endif
++
++pcre2_serialize_free(serialized_bytes);
++
+ /* The "push" control requests that the compiled pattern be remembered on a
+ stack. This is mainly for testing the serialization functionality. */
+
diff --git a/src/config.h.generic b/src/config.h.generic
index 5380525..789ef2c 100644
--- a/src/config.h.generic
+++ b/src/config.h.generic
@@ -250,7 +250,7 @@ surrounded by #ifndef/#endif lines so that the value can be overridden by -D. */
#define PACKAGE_NAME "PCRE2"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "PCRE2 10.48-RC1"
+#define PACKAGE_STRING "PCRE2 10.48"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "pcre2"
@@ -259,7 +259,7 @@ surrounded by #ifndef/#endif lines so that the value can be overridden by -D. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "10.48-RC1"
+#define PACKAGE_VERSION "10.48"
/* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested
parentheses (of any kind) in a pattern. This limits the amount of system
@@ -478,7 +478,7 @@ surrounded by #ifndef/#endif lines so that the value can be overridden by -D. */
#endif
/* Version number of package */
-#define VERSION "10.48-RC1"
+#define VERSION "10.48"
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
diff --git a/src/pcre2.h.generic b/src/pcre2.h.generic
index 283d61a..f171bbd 100644
--- a/src/pcre2.h.generic
+++ b/src/pcre2.h.generic
@@ -43,8 +43,8 @@ POSSIBILITY OF SUCH DAMAGE.
#define PCRE2_MAJOR 10
#define PCRE2_MINOR 48
-#define PCRE2_PRERELEASE -RC1
-#define PCRE2_DATE 2026-08-27
+#define PCRE2_PRERELEASE
+#define PCRE2_DATE 2026-08-31
/* When an application links to a PCRE2 DLL in Windows, the symbols that are
imported have to be identified as such. When building PCRE2, the appropriate
diff --git a/src/pcre2_compile.c b/src/pcre2_compile.c
index 1081cf6..32cb32f 100644
--- a/src/pcre2_compile.c
+++ b/src/pcre2_compile.c
@@ -6195,7 +6195,8 @@ for (;; pptr++)
if (meta < META_ASTERISK || meta > META_MINMAX_QUERY)
{
- if (OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code))
+ if (*lengthptr > OFLOW_MAX ||
+ OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code))
{
*errorcodeptr = ERR20; /* Integer overflow */
cb->erroroffset = 0;
@@ -8802,7 +8803,8 @@ for (;;)
*reqcuflagsptr = reqcuflags;
if (lengthptr != NULL)
{
- if (OFLOW_MAX - *lengthptr < length)
+ if (*lengthptr > MAX_PATTERN_SIZE ||
+ MAX_PATTERN_SIZE - *lengthptr < length)
{
*errorcodeptr = ERR20;
return 0;
@@ -8825,6 +8827,19 @@ for (;;)
{
code = *codeptr + 1 + LINK_SIZE + skipunits;
length += 1 + LINK_SIZE;
+
+ /* Move the accumulated length into *lengthptr, providing the next call to
+ compile_branch with as much space in &length and &code as the first did. */
+
+ if (*lengthptr > MAX_PATTERN_SIZE ||
+ MAX_PATTERN_SIZE - *lengthptr < length)
+ {
+ *errorcodeptr = ERR20;
+ cb->erroroffset = 0;
+ return 0;
+ }
+ *lengthptr += length;
+ length = 0;
}
else
{
@@ -10851,7 +10866,8 @@ if (errorcode != 0) goto HAD_CB_ERROR; /* Offset is in cb.erroroffset */
#if defined SUPPORT_WIDE_CHARS
PCRE2_ASSERT((cb.char_lists_size & 0x3) == 0);
if (length > MAX_PATTERN_SIZE ||
- MAX_PATTERN_SIZE - length < (cb.char_lists_size / sizeof(PCRE2_UCHAR)))
+ BYTES2CU(cb.char_lists_size) > MAX_PATTERN_SIZE ||
+ MAX_PATTERN_SIZE - length < BYTES2CU(cb.char_lists_size))
#else
if (length > MAX_PATTERN_SIZE)
#endif
@@ -10876,11 +10892,36 @@ if (cb.char_lists_size != 0)
/* Align to 32 bit first. This ensures the
allocated area will also be 32 bit aligned. */
re_blocksize = (PCRE2_SIZE)CLIST_ALIGN_TO(re_blocksize, sizeof(uint32_t));
+#else
+ /* Already 32 bit aligned. */
#endif
+
+ /* We have bounded the length and BYTES2CU(char_lists_size) to
+ MAX_PATTERN_SIZE units, however (with 32-bit code units) char_lists_size
+ in bytes could still be extremely close to (or greater than) SIZE_MAX, so
+ we require another overflow check. */
+
+ if (cb.char_lists_size > PCRE2_SIZE_MAX - re_blocksize)
+ {
+ errorcode = ERR20;
+ cb.erroroffset = 0;
+ goto HAD_CB_ERROR;
+ }
+
re_blocksize += cb.char_lists_size;
}
#endif
+if (length > BYTES2CU(PCRE2_SIZE_MAX - re_blocksize))
+ {
+ /* Given the current value of 2^30 for MAX_PATTERN_SIZE, this block is only
+ reachable when both PCRE2_CODE_UNIT_WIDTH >= 16 and sizeof(size_t) is
+ 32 bits. */
+ errorcode = ERR20;
+ cb.erroroffset = 0;
+ goto HAD_CB_ERROR;
+ }
+
re_blocksize += CU2BYTES(length);
if (re_blocksize > ccontext->max_pattern_compiled_length)
@@ -10890,7 +10931,15 @@ if (re_blocksize > ccontext->max_pattern_compiled_length)
goto HAD_CB_ERROR;
}
+if (sizeof(pcre2_real_code) > PCRE2_SIZE_MAX - re_blocksize)
+ {
+ errorcode = ERR20;
+ cb.erroroffset = 0;
+ goto HAD_CB_ERROR;
+ }
+
re_blocksize += sizeof(pcre2_real_code);
+
re = (pcre2_real_code *)
ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data);
if (re == NULL)
diff --git a/src/pcre2_compile_class.c b/src/pcre2_compile_class.c
index c6f30d6..c060664 100644
--- a/src/pcre2_compile_class.c
+++ b/src/pcre2_compile_class.c
@@ -498,7 +498,7 @@ static const uint32_t char_list_starts[] = {
static class_ranges *
compile_optimize_class(uint32_t *start_ptr, uint32_t options,
- uint32_t xoptions, compile_block *cb)
+ uint32_t xoptions, int *errorcodeptr, compile_block *cb)
{
class_ranges* cranges;
uint32_t *ptr;
@@ -538,12 +538,23 @@ PCRE2_ASSERT((range_list_size & 0x1) == 0);
total_size = range_list_size +
((range_list_size >= 2) ? CHAR_LIST_EXTRA_SIZE : 0);
+if (total_size > (PCRE2_SIZE_MAX - sizeof(class_ranges)) / sizeof(uint32_t))
+ {
+ *errorcodeptr = ERR20;
+ cb->erroroffset = 0;
+ return NULL;
+ }
cranges = cb->cx->memctl.malloc(
sizeof(class_ranges) + total_size * sizeof(uint32_t),
cb->cx->memctl.memory_data);
-if (cranges == NULL) return NULL;
+if (cranges == NULL)
+ {
+ *errorcodeptr = ERR21;
+ cb->erroroffset = 0;
+ return NULL;
+ }
cranges->header.next = NULL;
#ifdef PCRE2_DEBUG
@@ -1120,13 +1131,10 @@ if (utf)
{
if (lengthptr != NULL)
{
- cranges = compile_optimize_class(pptr, options, xoptions, cb);
+ cranges = compile_optimize_class(pptr, options, xoptions, errorcodeptr, cb);
if (cranges == NULL)
- {
- *errorcodeptr = ERR21;
return NULL;
- }
/* Caching the pre-processed character ranges. */
if (cb->last_data != NULL)
@@ -1759,18 +1767,17 @@ if ((xclass_props & XCLASS_REQUIRED) != 0)
*lengthptr += 1 + LINK_SIZE;
#endif
- cb->char_lists_size += char_lists_size;
-
- char_lists_size /= sizeof(PCRE2_UCHAR);
+ PCRE2_ASSERT(BYTES2CU(cb->char_lists_size) <= MAX_PATTERN_SIZE);
- /* Storage space for character lists is included
- in the maximum pattern size. */
- if (*lengthptr > MAX_PATTERN_SIZE ||
- MAX_PATTERN_SIZE - *lengthptr < char_lists_size)
+ if (char_lists_size > PCRE2_SIZE_MAX - cb->char_lists_size ||
+ BYTES2CU(char_lists_size) > MAX_PATTERN_SIZE ||
+ BYTES2CU(cb->char_lists_size) > MAX_PATTERN_SIZE - BYTES2CU(char_lists_size))
{
*errorcodeptr = ERR20; /* Pattern is too large */
return NULL;
}
+
+ cb->char_lists_size += char_lists_size;
}
else
{
@@ -1793,6 +1800,8 @@ if ((xclass_props & XCLASS_REQUIRED) != 0)
Each list is aligned to 32 bit with an optional unused
16 bit value at the beginning of the character list. */
+ PCRE2_ASSERT(char_lists_size <= PCRE2_SIZE_MAX - cb->char_lists_size);
+
cb->char_lists_size += char_lists_size;
data = (uint8_t*)cb->start_code - cb->char_lists_size;
diff --git a/src/pcre2_dfa_match.c b/src/pcre2_dfa_match.c
index 314e977..8e9512c 100644
--- a/src/pcre2_dfa_match.c
+++ b/src/pcre2_dfa_match.c
@@ -405,8 +405,8 @@ return (mb->callout)(cb, mb->callout_data);
/* This function is called when internal_dfa_match() is about to be called
recursively and there is insufficient working space left in the current
-workspace block. If there's an existing next block, use it; otherwise get a new
-block unless the heap limit is reached.
+workspace block. If there's a sufficiently large next block, use it; get a new
+block unless the heap limit is (or has been) reached.
Arguments:
rwsptr pointer to block pointer (updated)
@@ -422,9 +422,18 @@ more_workspace(RWS_anchor **rwsptr, unsigned int ovecsize, dfa_match_block *mb)
{
RWS_anchor *rws = *rwsptr;
RWS_anchor *new;
+uint32_t requested;
+
+PCRE2_ASSERT(ovecsize <= UINT32_MAX - RWS_RSIZE - RWS_ANCHOR_SIZE);
+requested = RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE;
if (rws->next != NULL)
{
+ /* Although the initial block is large, and subsequent ones try to double, the
+ heap limit may cause the last one to be smaller; in this case, we have already
+ hit the heap limit and allocating a larger block will not be possible. */
+ if (rws->next->size < requested)
+ return PCRE2_ERROR_HEAPLIMIT;
new = rws->next;
}
@@ -434,14 +443,30 @@ overflow. */
else
{
- uint32_t newsize = (rws->size >= UINT32_MAX/(sizeof(int)*2))? UINT32_MAX/sizeof(int) : rws->size * 2;
+ uint32_t newsize = (rws->size >= (UINT32_MAX/sizeof(int))/2)?
+ UINT32_MAX/sizeof(int) : rws->size * 2;
uint32_t newsizeK = newsize/(1024/sizeof(int));
- if (newsizeK + mb->heap_used > mb->heap_limit)
- newsizeK = (uint32_t)(mb->heap_limit - mb->heap_used);
- newsize = newsizeK*(1024/sizeof(int));
+ /* Clamp the allocation to the remaining heap allowance with care for overflows */
+
+ if (mb->heap_used >= mb->heap_limit)
+ {
+ newsize = 0;
+ newsizeK = 0;
+ }
+ else
+ {
+ PCRE2_SIZE availableK = mb->heap_limit - mb->heap_used;
+ /* newsize always capped at UINT32_MAX/sizeof(int), so newsizeK also capped;
+ and - if availableK is smaller - then multiplication to form newsize is safe */
+ if (newsizeK > availableK)
+ {
+ newsize = (uint32_t)(availableK*(1024/sizeof(int)));
+ newsizeK = availableK;
+ }
+ }
- if (newsize < RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE)
+ if (newsize < requested)
return PCRE2_ERROR_HEAPLIMIT;
new = mb->memctl.malloc(newsize*sizeof(int), mb->memctl.memory_data);
if (new == NULL) return PCRE2_ERROR_NOMEMORY;
@@ -2801,6 +2826,7 @@ for (;;)
local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE);
rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
@@ -2900,6 +2926,7 @@ for (;;)
local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE);
rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
@@ -2951,6 +2978,7 @@ for (;;)
local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
local_workspace = ((int *)local_offsets) + RWS_OVEC_RSIZE;
+ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_RSIZE);
rws->free -= RWS_RSIZE + RWS_OVEC_RSIZE;
/* Check for repeating a recursion without advancing the subject
@@ -3050,6 +3078,7 @@ for (;;)
local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE);
rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
if (codevalue == OP_BRAPOSZERO)
@@ -3149,6 +3178,7 @@ for (;;)
local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE);
rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
rc = internal_dfa_match(
diff --git a/src/pcre2_extuni.c b/src/pcre2_extuni.c
index 1b7f04b..fea098a 100644
--- a/src/pcre2_extuni.c
+++ b/src/pcre2_extuni.c
@@ -54,12 +54,12 @@ support, because some compilers do not like functionless source files. */
#ifndef SUPPORT_UNICODE
PCRE2_SPTR
-PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject,
+PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR check_subject,
PCRE2_SPTR end_subject, BOOL utf, int *xcount)
{
(void)c;
(void)eptr;
-(void)start_subject;
+(void)check_subject;
(void)end_subject;
(void)utf;
(void)xcount;
@@ -80,7 +80,7 @@ same behaviour.
Arguments:
c the first character
eptr pointer to next character
- start_subject pointer to start of subject
+ check_subject pointer to start of validated subject
end_subject pointer to end of subject
utf TRUE if in UTF mode
xcount pointer to count of additional characters,
@@ -90,7 +90,7 @@ Returns: pointer after the end of the sequence
*/
PCRE2_SPTR
-PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject,
+PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR check_subject,
PCRE2_SPTR end_subject, BOOL utf, int *xcount)
{
BOOL was_ep_ZWJ = FALSE;
@@ -121,7 +121,7 @@ while (eptr < end_subject)
/* bptr is pointing to the left-hand character */
- while (bptr > start_subject)
+ while (bptr > check_subject)
{
bptr--;
if (utf)
diff --git a/src/pcre2_match.c b/src/pcre2_match.c
index a5a8421..966576e 100644
--- a/src/pcre2_match.c
+++ b/src/pcre2_match.c
@@ -2895,7 +2895,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
else
{
GETCHARINCTEST(fc, Feptr);
- Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject, utf,
+ Feptr = PRIV(extuni)(fc, Feptr, mb->check_subject, mb->end_subject, utf,
NULL);
}
CHECK_PARTIAL();
@@ -3246,7 +3246,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
else
{
GETCHARINCTEST(fc, Feptr);
- Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject,
+ Feptr = PRIV(extuni)(fc, Feptr, mb->check_subject,
mb->end_subject, utf, NULL);
}
CHECK_PARTIAL();
@@ -4071,7 +4071,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
else
{
GETCHARINCTEST(fc, Feptr);
- Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject,
+ Feptr = PRIV(extuni)(fc, Feptr, mb->check_subject, mb->end_subject,
utf, NULL);
}
CHECK_PARTIAL();
@@ -4660,7 +4660,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
else
{
GETCHARINCTEST(fc, Feptr);
- Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject,
+ Feptr = PRIV(extuni)(fc, Feptr, mb->check_subject, mb->end_subject,
utf, NULL);
}
CHECK_PARTIAL();
@@ -6243,7 +6243,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
{
for (i = 0; i < Lmax; i++)
{
- if (Feptr == mb->start_subject)
+ if (Feptr <= mb->check_subject)
{
if (i < Lmin) RRETURN(MATCH_NOMATCH);
Lmax = i;
diff --git a/testdata/testinput10 b/testdata/testinput10
index d9e6ba8..bfa9dad 100644
--- a/testdata/testinput10
+++ b/testdata/testinput10
@@ -585,6 +585,16 @@
AAA\x80BXYZ
AAA\x80BBXYZ
+# Backward scans must not enter the invalid prefix before check_subject.
+
+/(?<=a{1,2})X/utf,match_invalid_utf
+\= Expect no match
+ \x80X
+
+/\X\X/utf,match_invalid_utf
+\= Expect no match
+ \x80\x{1f1e6}\x{1f1e7}
+
/(?<=(.))/utf,match_invalid_utf
x\x80
\x{10000}\x80
diff --git a/testdata/testinput12 b/testdata/testinput12
index 01cc76a..c4a89a2 100644
--- a/testdata/testinput12
+++ b/testdata/testinput12
@@ -498,6 +498,16 @@
/(..)(*scs:(1)ab$)/match_invalid_utf
ab\x{df00}cde
+# Backward scans must not enter the invalid prefix before check_subject.
+
+/(?<=a{1,2})X/utf,match_invalid_utf
+\= Expect no match
+ \x{dc00}X
+
+/\X\X/utf,match_invalid_utf
+\= Expect no match
+ \x{dc00}\x{1f1e6}\x{1f1e7}
+
/(?<=(.))/utf,match_invalid_utf
x\x{d800}
\x{10000}\x{dc00}
diff --git a/testdata/testinput6 b/testdata/testinput6
index f6f5cbf..197f6f7 100644
--- a/testdata/testinput6
+++ b/testdata/testinput6
@@ -5263,4 +5263,11 @@
abc\=replace=xyz
abc\=replace=xyz,substitute_matched
+# --------------
+
+# Test workspace resizing and workspace re-use
+
+/(*LIMIT_HEAP=4)(?=(?=(?=(?=(?=(?=(?=(?=a))(?R)))))))./
+ a\=dfa
+
# End of testinput6
diff --git a/testdata/testoutput10 b/testdata/testoutput10
index 393ac20..9e124e2 100644
--- a/testdata/testoutput10
+++ b/testdata/testoutput10
@@ -1779,6 +1779,18 @@ No match
AAA\x80BBXYZ
No match
+# Backward scans must not enter the invalid prefix before check_subject.
+
+/(?<=a{1,2})X/utf,match_invalid_utf
+\= Expect no match
+ \x80X
+No match
+
+/\X\X/utf,match_invalid_utf
+\= Expect no match
+ \x80\x{1f1e6}\x{1f1e7}
+No match
+
/(?<=(.))/utf,match_invalid_utf
x\x80
0:
diff --git a/testdata/testoutput12-16 b/testdata/testoutput12-16
index d235c11..b0676a1 100644
--- a/testdata/testoutput12-16
+++ b/testdata/testoutput12-16
@@ -1659,6 +1659,18 @@ No match
0: ab
1: ab
+# Backward scans must not enter the invalid prefix before check_subject.
+
+/(?<=a{1,2})X/utf,match_invalid_utf
+\= Expect no match
+ \x{dc00}X
+No match
+
+/\X\X/utf,match_invalid_utf
+\= Expect no match
+ \x{dc00}\x{1f1e6}\x{1f1e7}
+No match
+
/(?<=(.))/utf,match_invalid_utf
x\x{d800}
0:
diff --git a/testdata/testoutput12-32 b/testdata/testoutput12-32
index 725cb27..a97051a 100644
--- a/testdata/testoutput12-32
+++ b/testdata/testoutput12-32
@@ -1658,6 +1658,18 @@ No match
0: ab
1: ab
+# Backward scans must not enter the invalid prefix before check_subject.
+
+/(?<=a{1,2})X/utf,match_invalid_utf
+\= Expect no match
+ \x{dc00}X
+No match
+
+/\X\X/utf,match_invalid_utf
+\= Expect no match
+ \x{dc00}\x{1f1e6}\x{1f1e7}
+No match
+
/(?<=(.))/utf,match_invalid_utf
x\x{d800}
0:
diff --git a/testdata/testoutput6 b/testdata/testoutput6
index 8ecf004..4316c8a 100644
--- a/testdata/testoutput6
+++ b/testdata/testoutput6
@@ -8237,4 +8237,12 @@ Failed: error -42: pattern contains an item that is not supported for DFA matchi
abc\=replace=xyz,substitute_matched
Failed: error -41: function is not supported for DFA matching
+# --------------
+
+# Test workspace resizing and workspace re-use
+
+/(*LIMIT_HEAP=4)(?=(?=(?=(?=(?=(?=(?=(?=a))(?R)))))))./
+ a\=dfa
+Failed: error -63: heap limit exceeded
+
# End of testinput6
--
2.30.2